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

basic scenery data export in legacy text format

This commit is contained in:
tmj-fstate
2018-06-13 16:51:57 +02:00
parent e3f7ea33b3
commit 457de678c3
27 changed files with 1383 additions and 309 deletions

View File

@@ -423,13 +423,6 @@ TAnimModel::~TAnimModel()
SafeDelete(pRoot); SafeDelete(pRoot);
} }
bool TAnimModel::Init(TModel3d *pNewModel)
{
fBlinkTimer = double(Random(1000 * fOffTime)) / (1000 * fOffTime);
pModel = pNewModel;
return (pModel != nullptr);
}
bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture) bool TAnimModel::Init(std::string const &asName, std::string const &asReplacableTexture)
{ {
if( asReplacableTexture.substr( 0, 1 ) == "*" ) { if( asReplacableTexture.substr( 0, 1 ) == "*" ) {
@@ -445,17 +438,21 @@ bool TAnimModel::Init(std::string const &asName, std::string const &asReplacable
m_materialdata.textures_alpha = 0x31310031; m_materialdata.textures_alpha = 0x31310031;
} }
else{ else{
// tekstura nieprzezroczysta - nie renderować w cyklu // tekstura nieprzezroczysta - nie renderować w cyklu przezroczystych
m_materialdata.textures_alpha = 0x30300030; m_materialdata.textures_alpha = 0x30300030;
} }
// przezroczystych
return (Init(TModelsManager::GetModel(asName))); fBlinkTimer = double( Random( 1000 * fOffTime ) ) / ( 1000 * fOffTime );
pModel = TModelsManager::GetModel( asName );
return ( pModel != nullptr );
} }
bool TAnimModel::Load(cParser *parser, bool ter) bool TAnimModel::Load(cParser *parser, bool ter)
{ // rozpoznanie wpisu modelu i ustawienie świateł { // rozpoznanie wpisu modelu i ustawienie świateł
std::string name = parser->getToken<std::string>(); std::string name = parser->getToken<std::string>();
std::string texture = parser->getToken<std::string>(false); // tekstura (zmienia na małe) std::string texture = parser->getToken<std::string>(); // tekstura (zmienia na małe)
replace_slashes( name );
if (!Init( name, texture )) if (!Init( name, texture ))
{ {
if (name != "notload") if (name != "notload")
@@ -504,7 +501,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
while( ( token != "" ) while( ( token != "" )
&& ( token != "endmodel" ) ) { && ( token != "endmodel" ) ) {
LightSet( i, std::stod( token ) ); // stan światła jest liczbą z ułamkiem LightSet( i, std::stof( token ) ); // stan światła jest liczbą z ułamkiem
++i; ++i;
token = ""; token = "";
@@ -563,15 +560,6 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
m_framestamp = Framestamp; m_framestamp = Framestamp;
}; };
// calculates piece's bounding radius
void
TAnimModel::radius_() {
if( pModel != nullptr ) {
m_area.radius = pModel->bounding_radius();
}
}
void TAnimModel::RaPrepare() void TAnimModel::RaPrepare()
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza { // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
bool state; // stan światła bool state; // stan światła
@@ -584,7 +572,11 @@ void TAnimModel::RaPrepare()
state = ( fBlinkTimer < fOnTime ); state = ( fBlinkTimer < fOnTime );
break; break;
case ls_Dark: // zapalone, gdy ciemno case ls_Dark: // zapalone, gdy ciemno
state = ( Global.fLuminance <= ( lsLights[i] - 3.0 ) ); state = (
Global.fLuminance <= (
lsLights[i] == 3.f ?
DefaultDarkThresholdLevel :
( lsLights[i] - 3.f ) ) );
break; break;
default: // zapalony albo zgaszony default: // zapalony albo zgaszony
state = (lightmode == ls_On); state = (lightmode == ls_On);
@@ -780,15 +772,17 @@ void TAnimModel::LightSet(int const n, float const v)
} }
case ls_Dark: { case ls_Dark: {
// zapalenie świateł zależne od oświetlenia scenerii // zapalenie świateł zależne od oświetlenia scenerii
if( v == 3.0 ) { /*
if( v == 3.f ) {
// standardowy próg zaplania // standardowy próg zaplania
lsLights[ n ] = 3.0 + DefaultDarkThresholdLevel; lsLights[ n ] = 3.f + DefaultDarkThresholdLevel;
} }
*/
break; break;
} }
} }
}; };
//---------------------------------------------------------------------------
void TAnimModel::AnimUpdate(double dt) void TAnimModel::AnimUpdate(double dt)
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane { // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
TAnimContainer *p = TAnimModel::acAnimList; TAnimContainer *p = TAnimModel::acAnimList;
@@ -798,4 +792,72 @@ void TAnimModel::AnimUpdate(double dt)
p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi p = p->acAnimNext; // na razie bez usuwania z listy, bo głównie obrotnica na nią wchodzi
} }
}; };
// radius() subclass details, calculates node's bounding radius
float
TAnimModel::radius_() {
return (
pModel ?
pModel->bounding_radius() :
0.f );
}
// serialize() subclass details, sends content of the subclass to provided stream
void
TAnimModel::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TAnimModel::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TAnimModel::export_as_text_( std::ostream &Output ) const {
// header
Output << "model ";
// location and rotation
Output
<< location().x << ' '
<< location().y << ' '
<< location().z << ' '
<< vAngle.y << ' ';
// 3d shape
auto modelfile { (
pModel ?
pModel->NameGet() + ".t3d" : // rainsted requires model file names to include an extension
"none" ) };
if( modelfile.find( szModelPath ) == 0 ) {
// don't include 'models/' in the path
modelfile.erase( 0, std::string{ szModelPath }.size() );
}
Output << modelfile << ' ';
// texture
auto texturefile { (
m_materialdata.replacable_skins[ 1 ] != null_handle ?
GfxRenderer.Material( m_materialdata.replacable_skins[ 1 ] ).name :
"none" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
Output << texturefile << ' ';
// light submodels activation configuration
if( iNumLights > 0 ) {
Output << "lights ";
for( int lightidx = 0; lightidx < iNumLights; ++lightidx ) {
Output << lsLights[ lightidx ] << ' ';
}
}
// footer
Output
<< "endmodel"
<< "\n";
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -122,7 +122,7 @@ class TAnimAdvanced
}; };
// opakowanie modelu, określające stan egzemplarza // opakowanie modelu, określające stan egzemplarza
class TAnimModel : public editor::basic_node { class TAnimModel : public scene::basic_node {
friend class opengl_renderer; friend class opengl_renderer;
@@ -133,15 +133,12 @@ public:
~TAnimModel(); ~TAnimModel();
// methods // methods
static void AnimUpdate( double dt ); static void AnimUpdate( double dt );
bool Init(TModel3d *pNewModel);
bool Init(std::string const &asName, std::string const &asReplacableTexture); bool Init(std::string const &asName, std::string const &asReplacableTexture);
bool Load(cParser *parser, bool ter = false); bool Load(cParser *parser, bool ter = false);
TAnimContainer * AddContainer(std::string const &Name); TAnimContainer * AddContainer(std::string const &Name);
TAnimContainer * GetContainer(std::string const &Name = ""); TAnimContainer * GetContainer(std::string const &Name = "");
void RaAnglesSet( glm::vec3 Angles ) { void RaAnglesSet( glm::vec3 Angles ) {
vAngle.x = Angles.x; vAngle = { Angles }; };
vAngle.y = Angles.y;
vAngle.z = Angles.z; };
void LightSet( int const n, float const v ); void LightSet( int const n, float const v );
void AnimationVND( void *pData, double a, double b, double c, double d ); void AnimationVND( void *pData, double a, double b, double c, double d );
bool TerrainLoaded(); bool TerrainLoaded();
@@ -159,16 +156,20 @@ public:
// members // members
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
protected:
// calculates piece's bounding radius
void
radius_();
private: private:
// methods // methods
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza
void Advanced(); void Advanced();
// radius() subclass details, calculates node's bounding radius
float radius_();
// serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
// members // members
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
TModel3d *pModel { nullptr }; TModel3d *pModel { nullptr };

View File

@@ -194,11 +194,90 @@ bool TEventLauncher::IsGlobal() const {
&& ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu && ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
} }
// calculates node's bounding radius // radius() subclass details, calculates node's bounding radius
void float
TEventLauncher::radius_() { TEventLauncher::radius_() {
m_area.radius = std::sqrt( dRadius ); return std::sqrt( dRadius );
}
// serialize() subclass details, sends content of the subclass to provided stream
void
TEventLauncher::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TEventLauncher::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TEventLauncher::export_as_text_( std::ostream &Output ) const {
// header
Output << "eventlauncher ";
// location
Output
<< location().x << ' '
<< location().y << ' '
<< location().z << ' ';
// activation radius
Output
<< ( dRadius > 0 ? std::sqrt( dRadius ) : dRadius ) << ' ';
// activation key
if( iKey != 0 ) {
auto const key { iKey & 0xff };
auto const modifier { ( iKey & 0xff00 ) >> 8 };
if( ( key >= GLFW_KEY_A ) && ( key <= GLFW_KEY_Z ) ) {
Output << static_cast<char>(( 'A' + key - GLFW_KEY_A + ( ( modifier & 1 ) == 0 ? 32 : 0 ) )) << ' ';
}
else if( ( key >= GLFW_KEY_0 ) && ( key <= GLFW_KEY_9 ) ) {
Output << static_cast<char>(( '0' + key - GLFW_KEY_0 )) << ' ';
}
}
else {
Output << "none ";
}
// activation interval or hour
if( DeltaTime != 0 ) {
// cyclical launcher
Output << -DeltaTime << ' ';
}
else {
// single activation at specified time
if( ( iHour < 0 )
&& ( iMinute < 0 ) ) {
Output << DeltaTime << ' ';
}
else {
// NOTE: activation hour might be affected by user-requested time offset
auto const timeoffset{ static_cast<int>( Global.ScenarioTimeOffset * 60 ) };
auto const adjustedtime{ clamp_circular( iHour * 60 + iMinute - timeoffset, 24 * 60 ) };
Output
<< ( adjustedtime / 60 ) % 24
<< ( adjustedtime % 60 )
<< ' ';
}
}
// associated event(s)
Output << ( asEvent1Name.empty() ? "none" : asEvent1Name ) << ' ';
Output << ( asEvent2Name.empty() ? "none" : asEvent2Name ) << ' ';
if( false == asMemCellName.empty() ) {
// conditional event
Output
<< "condition "
<< asMemCellName << ' '
<< szText << ' '
<< ( ( iCheckMask & conditional_memval1 ) != 0 ? to_string( fVal1 ) : "*" ) << ' '
<< ( ( iCheckMask & conditional_memval2 ) != 0 ? to_string( fVal2 ) : "*" ) << ' ';
}
// footer
Output
<< "end"
<< "\n";
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "Classes.h" #include "Classes.h"
#include "scenenode.h" #include "scenenode.h"
class TEventLauncher : public editor::basic_node { class TEventLauncher : public scene::basic_node {
public: public:
// constructor // constructor
@@ -37,12 +37,17 @@ public:
int iCheckMask { 0 }; int iCheckMask { 0 };
double dRadius { 0.0 }; double dRadius { 0.0 };
protected:
// calculates node's bounding radius
void
radius_();
private: private:
// methods
// radius() subclass details, calculates node's bounding radius
float radius_();
// serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
// members // members
int iKey { 0 }; int iKey { 0 };
double DeltaTime { -1.0 }; double DeltaTime { -1.0 };

244
Event.cpp
View File

@@ -304,9 +304,9 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
if (token.find('#') != std::string::npos) if (token.find('#') != std::string::npos)
token.erase(token.find('#')); // obcięcie unikatowości token.erase(token.find('#')); // obcięcie unikatowości
win1250_to_ascii( token ); // get rid of non-ascii chars win1250_to_ascii( token ); // get rid of non-ascii chars
bEnabled = false; // nie do kolejki (dla SetVelocity też, ale jak jest do toru
// dowiązany)
Params[6].asCommand = cm_PassengerStopPoint; Params[6].asCommand = cm_PassengerStopPoint;
// nie do kolejki (dla SetVelocity też, ale jak jest do toru dowiązany)
bEnabled = false;
} }
else if (token == "SetVelocity") else if (token == "SetVelocity")
{ {
@@ -328,11 +328,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
bEnabled = false; bEnabled = false;
Params[6].asCommand = cm_ShuntVelocity; Params[6].asCommand = cm_ShuntVelocity;
} }
//else if (str == "SetProximityVelocity")
//{
// bEnabled = false;
// Params[6].asCommand = cm_SetProximityVelocity;
//}
else if (token == "OutsideStation") else if (token == "OutsideStation")
{ {
bEnabled = false; // ma być skanowny, aby AI nie przekraczało W5 bEnabled = false; // ma być skanowny, aby AI nie przekraczało W5
@@ -391,6 +386,11 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
} }
} }
} while( token.compare( "endevent" ) != 0 ); } while( token.compare( "endevent" ) != 0 );
while( paramidx < 8 ) {
// HACK: mark unspecified lights with magic value
Params[ paramidx ].asdouble = -2.0;
++paramidx;
}
break; break;
} }
case tp_Visible: // zmiana wyświetlania obiektu case tp_Visible: // zmiana wyświetlania obiektu
@@ -403,7 +403,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
case tp_Velocity: case tp_Velocity:
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
Params[0].asdouble = atof(token.c_str()) * 0.28; Params[0].asdouble = atof(token.c_str()) * ( 1000.0 / 3600.0 );
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
break; break;
@@ -420,7 +420,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
*parser >> token; *parser >> token;
break; break;
case tp_Exit: case tp_Exit:
asNodeName = ExchangeCharInString( asNodeName, '_', ' ' );
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
break; break;
@@ -605,6 +604,191 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
} }
}; };
// sends basic content of the class in legacy (text) format to provided stream
void
TEvent::export_as_text( std::ostream &Output ) const {
if( Type == tp_Unknown ) { return; }
// header
Output << "event ";
// name
Output << asName << ' ';
// type
std::vector<std::string> const types {
"unknown", "sound", "exit", "disable", "velocity", "animation", "lights",
"updatevalues", "getvalues", "putvalues", "switch", "dynvel", "trackvel",
"multiple", "addvalues", "copyvalues", "whois", "logvalues", "visible",
"voltage", "message", "friction" };
Output << types[ Type ] << ' ';
// delay
Output << fDelay << ' ';
// associated node
Output << ( asNodeName.empty() ? "none" : asNodeName ) << ' ';
// type-specific attributes
switch( Type ) {
case tp_AddValues:
case tp_UpdateValues: {
Output
<< ( ( iFlags & update_memstring ) == 0 ? "*" : Params[ 0 ].asText ) << ' '
<< ( ( iFlags & update_memval1 ) == 0 ? "*" : to_string( Params[ 1 ].asdouble ) ) << ' '
<< ( ( iFlags & update_memval2 ) == 0 ? "*" : to_string( Params[ 2 ].asdouble ) ) << ' ';
break;
}
case tp_CopyValues: {
// NOTE: there's no way to get the original parameter value if it doesn't point to existing memcell
Output
<< ( Params[ 9 ].asMemCell == nullptr ? "none" : Params[ 9 ].asMemCell->name() ) << ' '
<< ( iFlags & ( update_memstring | update_memval1 | update_memval2 ) ) << ' ';
break;
}
case tp_PutValues: {
Output
// location
<< Params[ 3 ].asdouble << ' '
<< Params[ 4 ].asdouble << ' '
<< Params[ 5 ].asdouble << ' '
// command
<< Params[ 0 ].asText << ' '
<< Params[ 1 ].asdouble << ' '
<< Params[ 2 ].asdouble << ' ';
break;
}
case tp_Multiple: {
// NOTE: conditional_anyelse won't work when event cap is removed
bool hasconditionalelse { false };
for( auto eventidx = 0; eventidx < 8; ++eventidx ) {
if( Params[ eventidx ].asEvent == nullptr ) { continue; }
if( ( iFlags & ( conditional_else << eventidx ) ) == 0 ) {
Output << Params[ eventidx ].asEvent->asName << ' ';
}
else {
// this event is executed as part of the 'else' block
hasconditionalelse = true;
}
}
// optional 'else' block
if( true == hasconditionalelse ) {
Output << "else ";
for( auto eventidx = 0; eventidx < 8; ++eventidx ) {
if( Params[ eventidx ].asEvent == nullptr ) { continue; }
if( ( iFlags & ( conditional_else << eventidx ) ) != 0 ) {
Output << Params[ eventidx ].asEvent->asName << ' ';
}
}
}
break;
}
case tp_Visible: {
Output << Params[ 0 ].asInt << ' ';
break;
}
case tp_Switch: {
Output << Params[ 0 ].asInt << ' ';
if( ( Params[ 1 ].asdouble != -1.0 )
|| ( Params[ 2 ].asdouble != -1.0 ) ) {
Output << Params[ 1 ].asdouble << ' ';
}
if( Params[ 2 ].asdouble != -1.0 ) {
Output << Params[ 2 ].asdouble << ' ';
}
break;
}
case tp_Lights: {
auto lightidx { 0 };
while( ( lightidx < iMaxNumLights )
&& ( Params[ lightidx ].asdouble > -2.0 ) ) {
Output << Params[ lightidx ].asdouble << ' ';
++lightidx;
}
break;
}
case tp_Animation: {
// animation type
Output << (
Params[ 0 ].asInt == 1 ? "rotate" :
Params[ 0 ].asInt == 2 ? "translate" :
// NOTE: .vmd animation doesn't preserve file name, can't be exported. TODO: fix this
Params[ 0 ].asInt == 8 ? "digital" :
"none" )
<< ' ';
// submodel
Output << (
Params[ 9 ].asAnimContainer != nullptr ?
Params[ 9 ].asAnimContainer->NameGet() :
"none" ) << ' ';
// animation parameters
Output
<< Params[ 1 ].asdouble << ' '
<< Params[ 2 ].asdouble << ' '
<< Params[ 3 ].asdouble << ' '
<< Params[ 4 ].asdouble << ' ';
break;
}
case tp_Sound: {
// playback mode
Output << Params[ 0 ].asInt << ' ';
// optional radio channel
if( Params[ 1 ].asdouble > 0.0 ) {
Output << Params[ 1 ].asdouble << ' ';
}
break;
}
case tp_DynVel:
case tp_TrackVel:
case tp_Voltage:
case tp_Friction: {
Output << Params[ 0 ].asdouble << ' ';
break;
}
case tp_Velocity: {
Output << Params[ 0 ].asdouble * ( 3600.0 / 1000.0 ) << ' ';
break;
}
case tp_WhoIs: {
Output
<< ( iFlags & ( update_memstring | update_memval1 | update_memval2 ) ) << ' ';
break;
}
default: {
break;
}
}
// optional conditions
// NOTE: for flexibility condition check and export is performed for all event types rather than only for these which support it currently
auto const isconditional { ( conditional_trackoccupied | conditional_trackfree | conditional_propability | conditional_memcompare ) };
if( ( ( iFlags & isconditional ) != 0 ) ) {
Output << "condition ";
if( ( iFlags & conditional_trackoccupied ) != 0 ) {
Output << "trackoccupied ";
}
else if( ( iFlags & conditional_trackfree ) != 0 ) {
Output << "trackfree ";
}
else if( ( iFlags & conditional_propability ) != 0 ) {
Output
<< "propability "
<< Params[ 10 ].asdouble << ' ';
}
else if( ( iFlags & conditional_memcompare ) != 0 ) {
Output
<< "memcompare "
<< ( ( iFlags & conditional_memstring ) == 0 ? "*" : Params[ 10 ].asText ) << ' '
<< ( ( iFlags & conditional_memval1 ) == 0 ? "*" : to_string( Params[ 11 ].asdouble ) ) << ' '
<< ( ( iFlags & conditional_memval2 ) == 0 ? "*" : to_string( Params[ 12 ].asdouble ) ) << ' ';
}
}
if( fRandomDelay != 0.0 ) {
Output
<< "randomdelay "
<< fRandomDelay << ' ';
}
// footer
Output
<< "endevent"
<< "\n";
}
void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) { void TEvent::AddToQuery( TEvent *Event, TEvent *&Start ) {
TEvent *target( Start ); TEvent *target( Start );
@@ -1002,6 +1186,10 @@ event_manager::CheckQuery() {
case tp_Lights: { case tp_Lights: {
if( m_workevent->Params[ 9 ].asModel ) { if( m_workevent->Params[ 9 ].asModel ) {
for( i = 0; i < iMaxNumLights; ++i ) { for( i = 0; i < iMaxNumLights; ++i ) {
if( m_workevent->Params[ i ].asdouble == -2.0 ) {
// processed all supplied values, bail out
break;
}
if( m_workevent->Params[ i ].asdouble >= 0 ) { if( m_workevent->Params[ i ].asdouble >= 0 ) {
// -1 zostawia bez zmiany // -1 zostawia bez zmiany
m_workevent->Params[ 9 ].asModel->LightSet( m_workevent->Params[ 9 ].asModel->LightSet(
@@ -1013,8 +1201,8 @@ event_manager::CheckQuery() {
break; break;
} }
case tp_Visible: { case tp_Visible: {
if( m_workevent->Params[ 9 ].asEditorNode ) if( m_workevent->Params[ 9 ].asSceneNode )
m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ 0 ].asInt > 0 ); m_workevent->Params[ 9 ].asSceneNode->visible( m_workevent->Params[ 0 ].asInt > 0 );
break; break;
} }
case tp_Velocity: { case tp_Velocity: {
@@ -1022,8 +1210,12 @@ event_manager::CheckQuery() {
break; break;
} }
case tp_Exit: { case tp_Exit: {
MessageBox( 0, m_workevent->asNodeName.c_str(), " THE END ", MB_OK ); // wyłączenie takie samo jak sekwencja F10 -> Y
Global.iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y MessageBox(
0,
ExchangeCharInString( m_workevent->asNodeName, '_', ' ' ).c_str(),
" THE END ",
MB_OK );
return false; return false;
} }
case tp_Sound: { case tp_Sound: {
@@ -1404,7 +1596,6 @@ event_manager::InitEvents() {
else { else {
ErrorLog( "Bad event: animation event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: animation event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
} }
event->asNodeName = "";
break; break;
} }
case tp_Lights: { case tp_Lights: {
@@ -1414,12 +1605,11 @@ event_manager::InitEvents() {
event->Params[ 9 ].asModel = instance; event->Params[ 9 ].asModel = instance;
else else
ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
event->asNodeName = "";
break; break;
} }
case tp_Visible: { case tp_Visible: {
// ukrycie albo przywrócenie obiektu // ukrycie albo przywrócenie obiektu
editor::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model scene::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
if( node == nullptr ) { if( node == nullptr ) {
// albo tory? // albo tory?
node = simulation::Paths.find( event->asNodeName ); node = simulation::Paths.find( event->asNodeName );
@@ -1429,12 +1619,11 @@ event_manager::InitEvents() {
node = simulation::Traction.find( event->asNodeName ); node = simulation::Traction.find( event->asNodeName );
} }
if( node != nullptr ) if( node != nullptr )
event->Params[ 9 ].asEditorNode = node; event->Params[ 9 ].asSceneNode = node;
else { else {
event->m_ignored = true; event->m_ignored = true;
ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" );
} }
event->asNodeName = "";
break; break;
} }
case tp_Switch: { case tp_Switch: {
@@ -1460,7 +1649,6 @@ event_manager::InitEvents() {
else { else {
ErrorLog( "Bad event: switch event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: switch event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
} }
event->asNodeName = "";
break; break;
} }
case tp_Sound: { case tp_Sound: {
@@ -1470,7 +1658,6 @@ event_manager::InitEvents() {
event->Params[ 9 ].tsTextSound = sound; event->Params[ 9 ].tsTextSound = sound;
else else
ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" );
event->asNodeName = "";
break; break;
} }
case tp_TrackVel: { case tp_TrackVel: {
@@ -1486,7 +1673,6 @@ event_manager::InitEvents() {
ErrorLog( "Bad event: track velocity event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: track velocity event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
} }
} }
event->asNodeName = "";
break; break;
} }
case tp_DynVel: { case tp_DynVel: {
@@ -1500,7 +1686,6 @@ event_manager::InitEvents() {
else else
ErrorLog( "Bad event: vehicle velocity event \"" + event->asName + "\" cannot find vehicle \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: vehicle velocity event \"" + event->asName + "\" cannot find vehicle \"" + event->asNodeName + "\"" );
} }
event->asNodeName = "";
break; break;
} }
case tp_Multiple: { case tp_Multiple: {
@@ -1548,7 +1733,6 @@ event_manager::InitEvents() {
else else
ErrorLog( "Bad event: voltage event \"" + event->asName + "\" cannot find power source \"" + event->asNodeName + "\"" ); ErrorLog( "Bad event: voltage event \"" + event->asName + "\" cannot find power source \"" + event->asNodeName + "\"" );
} }
event->asNodeName = "";
break; break;
} }
case tp_Message: { case tp_Message: {
@@ -1597,6 +1781,20 @@ event_manager::InitLaunchers() {
} }
} }
// sends basic content of the class in legacy (text) format to provided stream
void
event_manager::export_as_text( std::ostream &Output ) const {
Output << "// events\n";
for( auto const *event : m_events ) {
event->export_as_text( Output );
}
Output << "// event launchers\n";
for( auto const *launcher : m_launchers.sequence() ) {
launcher->export_as_text( Output );
}
}
// legacy method, verifies condition for specified event // legacy method, verifies condition for specified event
bool bool
event_manager::EventConditon( TEvent *Event ) { event_manager::EventConditon( TEvent *Event ) {

10
Event.h
View File

@@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/.
enum TEventType { enum TEventType {
tp_Unknown, tp_Unknown,
tp_Sound, tp_Sound,
tp_SoundPos,
tp_Exit, tp_Exit,
tp_Disable, tp_Disable,
tp_Velocity, tp_Velocity,
@@ -31,7 +30,6 @@ enum TEventType {
tp_TrackVel, tp_TrackVel,
tp_Multiple, tp_Multiple,
tp_AddValues, tp_AddValues,
// tp_Ignored, // NOTE: refactored to separate flag
tp_CopyValues, tp_CopyValues,
tp_WhoIs, tp_WhoIs,
tp_LogValues, tp_LogValues,
@@ -61,7 +59,7 @@ union TParam
{ {
void *asPointer; void *asPointer;
TMemCell *asMemCell; TMemCell *asMemCell;
editor::basic_node *asEditorNode; scene::basic_node *asSceneNode;
glm::dvec3 const *asLocation; glm::dvec3 const *asLocation;
TTrack *asTrack; TTrack *asTrack;
TAnimModel *asModel; TAnimModel *asModel;
@@ -103,6 +101,9 @@ public:
TEvent(std::string const &m = ""); TEvent(std::string const &m = "");
~TEvent(); ~TEvent();
void Load(cParser *parser, Math3D::vector3 const &org); void Load(cParser *parser, Math3D::vector3 const &org);
// sends basic content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
static void AddToQuery( TEvent *Event, TEvent *&Start ); static void AddToQuery( TEvent *Event, TEvent *&Start );
std::string CommandGet(); std::string CommandGet();
TCommandType Command(); TCommandType Command();
@@ -151,6 +152,9 @@ public:
// legacy method, initializes event launchers after deserialization from scenario file // legacy method, initializes event launchers after deserialization from scenario file
void void
InitLaunchers(); InitLaunchers();
// sends basic content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
private: private:
// types // types

View File

@@ -164,6 +164,41 @@ void TMemCell::AssignEvents(TEvent *e)
OnSent = e; OnSent = e;
}; };
// serialize() subclass details, sends content of the subclass to provided stream
void
TMemCell::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TMemCell::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TMemCell::export_as_text_( std::ostream &Output ) const {
// header
Output << "memcell ";
// location
Output
<< location().x << ' '
<< location().y << ' '
<< location().z << ' '
// cell data
<< szText << ' '
<< fValue1 << ' '
<< fValue2 << ' '
// associated track
<< ( asTrackName.empty() ? "none" : asTrackName ) << ' '
// footer
<< "endmemcell"
<< "\n";
}
// legacy method, initializes traction after deserialization from scenario file // legacy method, initializes traction after deserialization from scenario file

View File

@@ -13,10 +13,11 @@ http://mozilla.org/MPL/2.0/.
#include "scenenode.h" #include "scenenode.h"
#include "names.h" #include "names.h"
class TMemCell : public editor::basic_node { class TMemCell : public scene::basic_node {
public: public:
std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac
bool is_exportable { true }; // export helper; autogenerated cells don't need to be exported
explicit TMemCell( scene::node_data const &Nodedata ); explicit TMemCell( scene::node_data const &Nodedata );
@@ -49,6 +50,15 @@ public:
void AssignEvents(TEvent *e); void AssignEvents(TEvent *e);
private: private:
// methods
// serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
// members
// content // content
std::string szText; std::string szText;
double fValue1 { 0.0 }; double fValue1 { 0.0 };

View File

@@ -60,5 +60,8 @@ public:
type_sequence & type_sequence &
sequence() { sequence() {
return m_items; } return m_items; }
type_sequence const &
sequence() const {
return m_items; }
}; };

View File

@@ -18,8 +18,36 @@ http://mozilla.org/MPL/2.0/.
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// 101206 Ra: trapezoidalne drogi // helper, restores content of a 3d vector from provided input stream
// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0 // TODO: review and clean up the helper routines, there's likely some redundant ones
Math3D::vector3 LoadPoint( cParser &Input ) {
// pobranie współrzędnych punktu
Input.getTokens( 3 );
Math3D::vector3 point;
Input
>> point.x
>> point.y
>> point.z;
return point;
}
void
segment_data::deserialize( cParser &Input, Math3D::vector3 const &Offset ) {
points[ segment_data::point::start ] = LoadPoint( Input ) + Offset;
Input.getTokens();
Input >> rolls[ 0 ];
points[ segment_data::point::control1 ] = LoadPoint( Input );
points[ segment_data::point::control2 ] = LoadPoint( Input );
points[ segment_data::point::end ] = LoadPoint( Input ) + Offset;
Input.getTokens( 2 );
Input
>> rolls[ 1 ]
>> radius;
}
TSegment::TSegment(TTrack *owner) : TSegment::TSegment(TTrack *owner) :
pOwner( owner ) pOwner( owner )
@@ -62,6 +90,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
// poprawienie przechyłki // poprawienie przechyłki
fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń
fRoll2 = glm::radians(fNewRoll2); fRoll2 = glm::radians(fNewRoll2);
bCurve = bIsCurve;
if (Global.bRollFix) if (Global.bRollFix)
{ // Ra: poprawianie przechyłki { // Ra: poprawianie przechyłki
// Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi // Przechyłka powinna być na środku wewnętrznej szyny, a standardowo jest w osi
@@ -91,7 +120,6 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
// kąt w planie, żeby nie liczyć wielokrotnie // kąt w planie, żeby nie liczyć wielokrotnie
// Ra: ten kąt jeszcze do przemyślenia jest // Ra: ten kąt jeszcze do przemyślenia jest
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z); fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
bCurve = bIsCurve;
if (bCurve) if (bCurve)
{ // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne { // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne
vC = 3.0 * (CPointOut - Point1); // t^1 vC = 3.0 * (CPointOut - Point1); // t^1
@@ -99,9 +127,9 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
vA = Point2 - Point1 - vC - vB; // t^3 vA = Point2 - Point1 - vC - vB; // t^3
fLength = ComputeLength(); fLength = ComputeLength();
} }
else else {
fLength = (Point1 - Point2).Length(); fLength = ( Point1 - Point2 ).Length();
fStep = fNewStep; }
if (fLength <= 0) { if (fLength <= 0) {
ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" ); ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
@@ -111,17 +139,25 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
*/ */
} }
if( ( pOwner->eType == tt_Switch )
&& ( fStep * 3.0 > fLength ) ) {
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
fStep = fLength / 3.0;
}
fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie fStoop = std::atan2((Point2.y - Point1.y), fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
SafeDeleteArray(fTsBuffer);
fStep = fNewStep;
// NOTE: optionally replace this part with the commented version, after solving geometry issues with double switches
if( ( pOwner->eType == tt_Switch )
&& ( fStep * ( 3.0 * Global.SplineFidelity ) > fLength ) ) {
// NOTE: a workaround for too short switches (less than 3 segments) messing up animation/generation of blades
fStep = fLength / ( 3.0 * Global.SplineFidelity );
}
iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO
/*
iSegCount = (
pOwner->eType == tt_Switch ?
6 * Global.SplineFidelity :
static_cast<int>( std::ceil( fLength / fStep ) ) ); // potrzebne do VBO
*/
fStep = fLength / iSegCount; // update step to equalize size of individual pieces fStep = fLength / iSegCount; // update step to equalize size of individual pieces
SafeDeleteArray( fTsBuffer );
fTsBuffer = new double[ iSegCount + 1 ]; fTsBuffer = new double[ iSegCount + 1 ];
fTsBuffer[ 0 ] = 0.0; fTsBuffer[ 0 ] = 0.0;
for( int i = 1; i < iSegCount; ++i ) { for( int i = 1; i < iSegCount; ++i ) {

View File

@@ -14,6 +14,24 @@ http://mozilla.org/MPL/2.0/.
#include "openglgeometrybank.h" #include "openglgeometrybank.h"
#include "utilities.h" #include "utilities.h"
struct segment_data {
// types
enum point {
start = 0,
control1,
control2,
end
};
// members
std::array<glm::dvec3, 4> points {};
std::array<float, 2> rolls {};
float radius {};
// constructors
segment_data() = default;
// methods
void deserialize( cParser &Input, Math3D::vector3 const &Offset );
};
class TSegment class TSegment
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny) { // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
private: private:

521
Track.cpp
View File

@@ -343,14 +343,6 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
} }
} }
Math3D::vector3 LoadPoint(cParser *parser)
{ // pobranie współrzędnych punktu
Math3D::vector3 p;
parser->getTokens(3);
*parser >> p.x >> p.y >> p.z;
return p;
}
void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin) void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
{ // pobranie obiektu trajektorii ruchu { // pobranie obiektu trajektorii ruchu
Math3D::vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań Math3D::vector3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
@@ -473,20 +465,44 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
WriteLog("unvis"); WriteLog("unvis");
Init(); // ustawia SwitchExtension Init(); // ustawia SwitchExtension
double segsize = 5.0; // długość odcinka segmentowania double segsize = 5.0; // długość odcinka segmentowania
switch (eType)
{ // Ra: łuki segmentowane co 5m albo 314-kątem foremnym // path data
case tt_Table: // obrotnica jest prawie jak zwykły tor // all subtypes contain at least one path
m_paths.emplace_back();
m_paths.back().deserialize( *parser, pOrigin );
switch( eType ) {
case tt_Switch:
case tt_Cross:
case tt_Tributary: {
// these subtypes contain additional path
m_paths.emplace_back();
m_paths.back().deserialize( *parser, pOrigin );
break;
}
default: {
break;
}
}
switch (eType) {
// Ra: łuki segmentowane co 5m albo 314-kątem foremnym
case tt_Table: {
// obrotnica jest prawie jak zwykły tor
iAction |= 2; // flaga zmiany położenia typu obrotnica iAction |= 2; // flaga zmiany położenia typu obrotnica
case tt_Normal: }
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1 case tt_Normal: {
parser->getTokens(); // pobranie współrzędnych P1
*parser >> r1; // pobranie przechyłki w P1 auto const &path { m_paths[ 0 ] };
cp1 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych p1 = path.points[ segment_data::point::start ];
cp2 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2 cp1 = path.points[ segment_data::point::control1 ];
parser->getTokens(2); cp2 = path.points[ segment_data::point::control2 ];
*parser >> r2 >> fRadius; // pobranie przechyłki w P1 i promienia // pobranie współrzędnych P2
fRadius = fabs(fRadius); // we wpisie może być ujemny p2 = path.points[ segment_data::point::end ];
r1 = path.rolls[ 0 ];
r2 = path.rolls[ 1 ];
fRadius = std::abs( path.radius ); // we wpisie może być ujemny
if (iCategoryFlag & 1) if (iCategoryFlag & 1)
{ // zero na główce szyny { // zero na główce szyny
p1.y += 0.18; p1.y += 0.18;
@@ -502,7 +518,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
if( fRadius != 0 ) { if( fRadius != 0 ) {
// gdy podany promień // gdy podany promień
segsize = clamp( std::abs( fRadius ) * ( 0.02 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 ); segsize =
clamp(
std::abs( fRadius ) * ( 0.02 / Global.SplineFidelity ),
2.0 / Global.SplineFidelity,
10.0 / Global.SplineFidelity );
} }
else { else {
// HACK: crude check whether claimed straight is an actual straight piece // HACK: crude check whether claimed straight is an actual straight piece
@@ -512,7 +532,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
} }
else { else {
// HACK: divide roughly in 10 segments. // HACK: divide roughly in 10 segments.
segsize = clamp( ( p1 - p2 ).Length() * ( 0.1 / Global.SplineFidelity ), 2.0 / Global.SplineFidelity, 10.0 ); segsize =
clamp(
( p1 - p2 ).Length() * 0.1,
2.0 / Global.SplineFidelity,
10.0 / Global.SplineFidelity );
} }
} }
@@ -529,6 +553,7 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
if ((r1 != 0) || (r2 != 0)) if ((r1 != 0) || (r2 != 0))
iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu
if (eType == tt_Table) // obrotnica ma doklejkę if (eType == tt_Table) // obrotnica ma doklejkę
{ // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy { // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy
SwitchExtension->Segments[0]->Init(p1, p2, segsize); // kopia oryginalnego toru SwitchExtension->Segments[0]->Init(p1, p2, segsize); // kopia oryginalnego toru
@@ -549,56 +574,92 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
fTexRatio2 = w / h; // proporcja boków fTexRatio2 = w / h; // proporcja boków
} }
break; break;
}
case tt_Cross: // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi case tt_Cross: {
segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi
// segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie
}
case tt_Tributary: // dopływ case tt_Tributary: // dopływ
case tt_Switch: // zwrotnica case tt_Switch: { // zwrotnica
iAction |= 1; // flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg iAction |= 1; // flaga zmiany położenia typu zwrotnica lub skrzyżowanie dróg
// problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę // problemy z animacją iglic powstaje, gdzy odcinek prosty ma zmienną przechyłkę
// wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą // wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą
// Ra: na razie nie podejmuję się przerabiania iglic // Ra: na razie nie podejmuję się przerabiania iglic
// SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę // SwitchExtension=new TSwitchExtension(this,eType==tt_Cross?6:2); //zwrotnica ma doklejkę
auto const &path { m_paths[ 0 ] };
p1 = path.points[ segment_data::point::start ];
// pobranie współrzędnych punktów kontrolnych
cp1 = path.points[ segment_data::point::control1 ];
cp2 = path.points[ segment_data::point::control2 ];
// pobranie współrzędnych P2
p2 = path.points[ segment_data::point::end ];
r1 = path.rolls[ 0 ];
r2 = path.rolls[ 1 ];
fRadiusTable[0] = std::abs( path.radius ); // we wpisie może być ujemny
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
parser->getTokens();
*parser >> r1;
cp1 = LoadPoint(parser);
cp2 = LoadPoint(parser);
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
parser->getTokens(2);
*parser >> r2 >> fRadiusTable[0];
fRadiusTable[0] = fabs(fRadiusTable[0]); // we wpisie może być ujemny
if (iCategoryFlag & 1) if (iCategoryFlag & 1)
{ // zero na główce szyny { // zero na główce szyny
p1.y += 0.18; p1.y += 0.18;
p2.y += 0.18; p2.y += 0.18;
// na przechyłce doliczyć jeszcze pół przechyłki? // na przechyłce doliczyć jeszcze pół przechyłki?
} }
if (fRadiusTable[0] > 0)
segsize = clamp( 0.2 + fRadiusTable[0] * 0.02, 2.0, 5.0 );
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne
{ // jak promień zerowy, to przeliczamy punkty kontrolne
cp1 = (p1 + p1 + p2) / 3.0 - p1; // jak jest prosty, to się zoptymalizuje
cp2 = (p1 + p2 + p2) / 3.0 - p2;
segsize = 5.0;
} // ułomny prosty
if (!(cp1 == Math3D::vector3(0, 0, 0)) && !(cp2 == Math3D::vector3(0, 0, 0))) if( eType != tt_Cross ) {
SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2); // dla skrzyżowań muszą być podane kontrolne
else if( ( ( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ).Length() < 0.02 )
SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2); || ( ( ( p1 + p2 + p2 ) / 3.0 - p2 + cp1 ).Length() < 0.02 ) ) {
// "prostowanie" prostych z kontrolnymi, dokładność 2cm
cp1 = cp2 = Math3D::vector3( 0, 0, 0 );
}
}
if( fRadiusTable[ 0 ] != 0 ) {
// gdy podany promień
segsize =
clamp(
std::abs( fRadiusTable[ 0 ] ) * ( 0.02 / Global.SplineFidelity ),
2.0 / Global.SplineFidelity,
10.0 / Global.SplineFidelity );
}
else {
// HACK: crude check whether claimed straight is an actual straight piece
if( ( cp1 == Math3D::vector3() )
&& ( cp2 == Math3D::vector3() ) ) {
segsize = 10.0; // for straights, 10m per segment works good enough
}
else {
// HACK: divide roughly in 10 segments.
segsize =
clamp(
( p1 - p2 ).Length() * 0.1,
2.0 / Global.SplineFidelity,
10.0 / Global.SplineFidelity );
}
}
if( ( cp1 == Math3D::vector3( 0, 0, 0 ) )
&& ( cp2 == Math3D::vector3( 0, 0, 0 ) ) ) {
// Ra: hm, czasem dla prostego są podane...
// gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
SwitchExtension->Segments[ 0 ]->Init( p1, p2, segsize, r1, r2 );
}
else {
// gdy łuk (ustawia bCurve=true)
SwitchExtension->Segments[ 0 ]->Init( p1, cp1 + p1, cp2 + p2, p2, segsize, r1, r2 );
}
auto const &path2 { m_paths[ 1 ] };
p3 = path2.points[ segment_data::point::start ];
// pobranie współrzędnych punktów kontrolnych
cp3 = path2.points[ segment_data::point::control1 ];
cp4 = path2.points[ segment_data::point::control2 ];
// pobranie współrzędnych P2
p4 = path2.points[ segment_data::point::end ];
r3 = path2.rolls[ 0 ];
r4 = path2.rolls[ 1 ];
fRadiusTable[1] = std::abs( path2.radius ); // we wpisie może być ujemny
p3 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P3
parser->getTokens();
*parser >> r3;
cp3 = LoadPoint(parser);
cp4 = LoadPoint(parser);
p4 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P4
parser->getTokens(2);
*parser >> r4 >> fRadiusTable[1];
fRadiusTable[1] = fabs(fRadiusTable[1]); // we wpisie może być ujemny
if (iCategoryFlag & 1) if (iCategoryFlag & 1)
{ // zero na główce szyny { // zero na główce szyny
p3.y += 0.18; p3.y += 0.18;
@@ -606,25 +667,54 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
// na przechyłce doliczyć jeszcze pół przechyłki? // na przechyłce doliczyć jeszcze pół przechyłki?
} }
if (fRadiusTable[1] > 0) if( eType != tt_Cross ) {
segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 0.02, 2.0, 5.0 ); // dla skrzyżowań muszą być podane kontrolne
if( ( ( ( p3 + p3 + p4 ) / 3.0 - p3 - cp3 ).Length() < 0.02 )
else if (eType != tt_Cross) // dla skrzyżowań muszą być podane kontrolne || ( ( ( p3 + p4 + p4 ) / 3.0 - p4 + cp3 ).Length() < 0.02 ) ) {
{ // jak promień zerowy, to przeliczamy punkty kontrolne // "prostowanie" prostych z kontrolnymi, dokładność 2cm
cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje cp3 = cp4 = Math3D::vector3( 0, 0, 0 );
cp4 = (p3 + p4 + p4) / 3.0 - p4; }
segsize = 5.0; }
} // ułomny prosty
if( fRadiusTable[ 1 ] != 0 ) {
if (!(cp3 == Math3D::vector3(0, 0, 0)) && !(cp4 == Math3D::vector3(0, 0, 0))) // gdy podany promień
{ // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym segsize =
if (eType != tt_Cross) clamp(
SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4); std::abs( fRadiusTable[ 1 ] ) * ( 0.02 / Global.SplineFidelity ),
else 2.0 / Global.SplineFidelity,
SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3); // odwrócony 10.0 / Global.SplineFidelity );
}
else {
// HACK: crude check whether claimed straight is an actual straight piece
if( ( cp3 == Math3D::vector3() )
&& ( cp4 == Math3D::vector3() ) ) {
segsize = 10.0; // for straights, 10m per segment works good enough
}
else {
// HACK: divide roughly in 10 segments.
segsize =
clamp(
( p3 - p4 ).Length() * 0.1,
2.0 / Global.SplineFidelity,
10.0 / Global.SplineFidelity );
}
}
if( ( cp3 == Math3D::vector3( 0, 0, 0 ) )
&& ( cp4 == Math3D::vector3( 0, 0, 0 ) ) ) {
// Ra: hm, czasem dla prostego są podane...
// gdy prosty, kontrolne wyliczane przy zmiennej przechyłce
SwitchExtension->Segments[ 1 ]->Init( p3, p4, segsize, r3, r4 );
}
else {
if( eType != tt_Cross ) {
SwitchExtension->Segments[ 1 ]->Init( p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4 );
}
else {
// dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym
SwitchExtension->Segments[ 1 ]->Init( p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3 ); // odwrócony
}
} }
else
SwitchExtension->Segments[1]->Init(p3, p4, segsize, r3, r4);
if (eType == tt_Cross) if (eType == tt_Cross)
{ // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty { // Ra 2014-07: dla skrzyżowań będą dodatkowe segmenty
@@ -646,10 +736,10 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
{ {
Math3D::vector3 v1, v2; Math3D::vector3 v1, v2;
double a1, a2; double a1, a2;
v1 = SwitchExtension->Segments[0]->FastGetPoint_1() - v1 = SwitchExtension->Segments[0]->FastGetPoint_1()
SwitchExtension->Segments[0]->FastGetPoint_0(); - SwitchExtension->Segments[0]->FastGetPoint_0();
v2 = SwitchExtension->Segments[1]->FastGetPoint_1() - v2 = SwitchExtension->Segments[1]->FastGetPoint_1()
SwitchExtension->Segments[1]->FastGetPoint_0(); - SwitchExtension->Segments[1]->FastGetPoint_0();
a1 = atan2(v1.x, v1.z); a1 = atan2(v1.x, v1.z);
a2 = atan2(v2.x, v2.z); a2 = atan2(v2.x, v2.z);
a2 = a2 - a1; a2 = a2 - a1;
@@ -661,6 +751,9 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
} }
break; break;
} }
}
// optional attributes
parser->getTokens(); parser->getTokens();
*parser >> token; *parser >> token;
str = token; str = token;
@@ -707,9 +800,9 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
parser->getTokens(); parser->getTokens();
*parser >> fVelocity; //*0.28; McZapkie-010602 *parser >> fVelocity; //*0.28; McZapkie-010602
if (SwitchExtension) // jeśli tor ruchomy if (SwitchExtension) // jeśli tor ruchomy
if (std::fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio if (std::abs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
SwitchExtension->fVelocity = static_cast<float>(fVelocity); // zapamiętanie głównego ograniczenia; a // zapamiętanie głównego ograniczenia; a np. -40 ogranicza tylko na bok
// np. -40 ogranicza tylko na bok SwitchExtension->fVelocity = static_cast<float>(fVelocity);
} }
else if (str == "isolated") else if (str == "isolated")
{ // obwód izolowany, do którego tor należy { // obwód izolowany, do którego tor należy
@@ -777,20 +870,25 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
} }
// TODO: refactor this mess // TODO: refactor this mess
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit )
{ {
bool bError = false; bool bError = false;
if( NewEvent0 == nullptr ) { if( NewEvent0 == nullptr ) {
if( false == asEvent0Name.empty() ) { if( false == asEvent0Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEvent0 == nullptr ) { if( evEvent0 == nullptr ) {
evEvent0 = NewEvent0; evEvent0 = NewEvent0;
/*
// preserve event names, we'll need them if we want the scenario export to be unaffected by missing events and such
asEvent0Name = ""; asEvent0Name = "";
*/
iEvents |= 1; // sumaryczna informacja o eventach iEvents |= 1; // sumaryczna informacja o eventach
} }
else { else {
@@ -801,14 +899,18 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
if( NewEvent1 == nullptr ) { if( NewEvent1 == nullptr ) {
if( false == asEvent1Name.empty() ) { if( false == asEvent1Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEvent1 == nullptr ) { if( evEvent1 == nullptr ) {
evEvent1 = NewEvent1; evEvent1 = NewEvent1;
/*
asEvent1Name = ""; asEvent1Name = "";
*/
iEvents |= 2; // sumaryczna informacja o eventach iEvents |= 2; // sumaryczna informacja o eventach
} }
else { else {
@@ -819,14 +921,18 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
if( NewEvent2 == nullptr ) { if( NewEvent2 == nullptr ) {
if( false == asEvent2Name.empty() ) { if( false == asEvent2Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEvent2 == nullptr ) { if( evEvent2 == nullptr ) {
evEvent2 = NewEvent2; evEvent2 = NewEvent2;
/*
asEvent2Name = ""; asEvent2Name = "";
*/
iEvents |= 4; // sumaryczna informacja o eventach iEvents |= 4; // sumaryczna informacja o eventach
} }
else { else {
@@ -838,20 +944,25 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
return ( bError == false ); return ( bError == false );
} }
bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit)
{ {
bool bError = false; bool bError = false;
if( NewEvent0 == nullptr ) { if( NewEvent0 == nullptr ) {
if( false == asEventall0Name.empty() ) { if( false == asEventall0Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEventall0 == nullptr ) { if( evEventall0 == nullptr ) {
evEventall0 = NewEvent0; evEventall0 = NewEvent0;
/*
// preserve event names, we'll need them if we want the scenario export to be unaffected by missing events and such
asEventall0Name = ""; asEventall0Name = "";
*/
iEvents |= 8; // sumaryczna informacja o eventach iEvents |= 8; // sumaryczna informacja o eventach
} }
else { else {
@@ -862,14 +973,18 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
if( NewEvent1 == nullptr ) { if( NewEvent1 == nullptr ) {
if( false == asEventall1Name.empty() ) { if( false == asEventall1Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEventall1 == nullptr ) { if( evEventall1 == nullptr ) {
evEventall1 = NewEvent1; evEventall1 = NewEvent1;
/*
asEventall1Name = ""; asEventall1Name = "";
*/
iEvents |= 16; // sumaryczna informacja o eventach iEvents |= 16; // sumaryczna informacja o eventach
} }
else { else {
@@ -880,14 +995,18 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
if( NewEvent2 == nullptr ) { if( NewEvent2 == nullptr ) {
if( false == asEventall2Name.empty() ) { if( false == asEventall2Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true; bError = true;
if( true == Explicit ) {
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
}
} }
} }
else { else {
if( evEventall2 == nullptr ) { if( evEventall2 == nullptr ) {
evEventall2 = NewEvent2; evEventall2 = NewEvent2;
/*
asEventall2Name = ""; asEventall2Name = "";
*/
iEvents |= 32; // sumaryczna informacja o eventach iEvents |= 32; // sumaryczna informacja o eventach
} }
else { else {
@@ -1404,6 +1523,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
{szyna[ i ].texture.x, 0.f} }; {szyna[ i ].texture.x, 0.f} };
} }
// TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers // TODO, TBD: change all track geometry to triangles, to allow packing data in less, larger buffers
auto const bladelength { 2 * Global.SplineFidelity };
if (SwitchExtension->RightSwitch) if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
gfx::vertex_array vertices; gfx::vertex_array vertices;
@@ -1412,11 +1532,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
// left blade // left blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
} }
@@ -1425,11 +1545,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
// right blade // right blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
} }
@@ -1442,11 +1562,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_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 ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, 2 ); // prawa szyna za iglicą SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts2, nnumPts, fTexLength, 1.0, bladelength ); // prawa szyna za iglicą
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
// right blade // right blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
} }
@@ -1455,11 +1575,11 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_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 ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, 2 ); // lewa szyna za iglicą SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts1, nnumPts, fTexLength, 1.0, bladelength ); // lewa szyna za iglicą
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
// left blade // left blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) ); Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
vertices.clear(); vertices.clear();
} }
@@ -2220,9 +2340,13 @@ bool TTrack::Switch(int i, float const t, float const d)
iNextDirection = SwitchExtension->iNextDirection[i]; iNextDirection = SwitchExtension->iNextDirection[i];
iPrevDirection = SwitchExtension->iPrevDirection[i]; iPrevDirection = SwitchExtension->iPrevDirection[i];
fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru
if (SwitchExtension->fVelocity <= if( SwitchExtension->fVelocity <= -2 ) {
-2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
fVelocity = i ? -SwitchExtension->fVelocity : -1; fVelocity = i ? -SwitchExtension->fVelocity : -1;
}
else {
fVelocity = SwitchExtension->fVelocity;
}
if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) : if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) :
true) // jeśli nie dodane do animacji true) // jeśli nie dodane do animacji
{ // nie ma się co bawić { // nie ma się co bawić
@@ -2455,17 +2579,18 @@ TTrack * TTrack::RaAnimate()
gfx::vertex_array vertices; gfx::vertex_array vertices;
auto const bladelength { 2 * Global.SplineFidelity };
if (SwitchExtension->RightSwitch) if (SwitchExtension->RightSwitch)
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa { // nowa wersja z SPKS, ale odwrotnie lewa/prawa
if( m_material1 ) { if( m_material1 ) {
// left blade // left blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, SwitchExtension->fOffset2 );
GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
vertices.clear(); vertices.clear();
} }
if( m_material2 ) { if( m_material2 ) {
// right blade // right blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -fMaxOffset + SwitchExtension->fOffset1 ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -fMaxOffset + SwitchExtension->fOffset1 );
GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
vertices.clear(); vertices.clear();
} }
@@ -2473,13 +2598,13 @@ TTrack * TTrack::RaAnimate()
else { // lewa działa lepiej niż prawa else { // lewa działa lepiej niż prawa
if( m_material1 ) { if( m_material1 ) {
// right blade // right blade
SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, 2, -SwitchExtension->fOffset2 ); SwitchExtension->Segments[ 0 ]->RenderLoft( vertices, m_origin, rpts4, -nnumPts, fTexLength, 1.0, 0, bladelength, -SwitchExtension->fOffset2 );
GfxRenderer.Replace( vertices, Geometry1[ 2 ] ); GfxRenderer.Replace( vertices, Geometry1[ 2 ] );
vertices.clear(); vertices.clear();
} }
if( m_material2 ) { if( m_material2 ) {
// left blade // left blade
SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, 2, fMaxOffset - SwitchExtension->fOffset1 ); SwitchExtension->Segments[ 1 ]->RenderLoft( vertices, m_origin, rpts3, -nnumPts, fTexLength, 1.0, 0, bladelength, fMaxOffset - SwitchExtension->fOffset1 );
GfxRenderer.Replace( vertices, Geometry2[ 2 ] ); GfxRenderer.Replace( vertices, Geometry2[ 2 ] );
vertices.clear(); vertices.clear();
} }
@@ -2659,32 +2784,188 @@ TTrack::endpoints() const {
} }
} }
// calculates path's bounding radius // radius() subclass details, calculates node's bounding radius
void float
TTrack::radius_() { TTrack::radius_() {
auto const points = endpoints(); auto const points { endpoints() };
auto radius { 0.f };
for( auto &point : points ) { for( auto &point : points ) {
m_area.radius = std::max( radius = std::max(
m_area.radius, radius,
static_cast<float>( glm::length( m_area.center - point ) ) ); // extra margin to prevent driven vehicle from flicking static_cast<float>( glm::length( m_area.center - point ) ) ); // extra margin to prevent driven vehicle from flicking
} }
return radius;
}
// serialize() subclass details, sends content of the subclass to provided stream
void
TTrack::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TTrack::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TTrack::export_as_text_( std::ostream &Output ) const {
// header
Output << "track ";
// type
Output << (
eType == tt_Normal ? (
iCategoryFlag == 1 ? "normal" :
iCategoryFlag == 2 ? "road" :
iCategoryFlag == 4 ? "river" :
"none" ) :
eType == tt_Switch ? "switch" :
eType == tt_Cross ? "cross" :
eType == tt_Table ? "turn" :
eType == tt_Tributary ? "tributary" :
"none" )
<< ' ';
// basic attributes
Output
<< Length() << ' '
<< fTrackWidth << ' '
<< fFriction << ' '
<< fSoundDistance << ' '
<< iQualityFlag << ' '
<< iDamageFlag << ' ';
// environment
Output << (
eEnvironment == e_flat ? "flat" :
eEnvironment == e_bridge ? "bridge" :
eEnvironment == e_tunnel ? "tunnel" :
eEnvironment == e_bank ? "bank" :
eEnvironment == e_canyon ? "canyon" :
eEnvironment == e_mountains ? "mountains" :
"none" )
<< ' ';
// visibility
// NOTE: 'invis' would be less wrong than 'unvis', but potentially incompatible with old 3rd party tools
Output << ( m_visible ? "vis" : "unvis" ) << ' ';
if( m_visible ) {
// texture parameters are supplied only if the path is set as visible
auto texturefile { (
m_material1 != null_handle ?
GfxRenderer.Material( m_material1 ).name :
"none" ) };
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
Output
<< texturefile << ' '
<< fTexLength << ' ';
texturefile = (
m_material2 != null_handle ?
GfxRenderer.Material( m_material2 ).name :
"none" );
if( texturefile.find( szTexturePath ) == 0 ) {
// don't include 'textures/' in the path
texturefile.erase( 0, std::string{ szTexturePath }.size() );
}
Output << texturefile << ' ';
Output
<< (fTexHeight1 - fTexHeightOffset ) * ( ( iCategoryFlag & 4 ) ? -1 : 1 ) << ' '
<< fTexWidth << ' '
<< fTexSlope << ' ';
}
// path data
for( auto const &path : m_paths ) {
Output
<< path.points[ segment_data::point::start ].x << ' '
<< path.points[ segment_data::point::start ].y << ' '
<< path.points[ segment_data::point::start ].z << ' '
<< path.rolls[ 0 ] << ' '
<< path.points[ segment_data::point::control1 ].x << ' '
<< path.points[ segment_data::point::control1 ].y << ' '
<< path.points[ segment_data::point::control1 ].z << ' '
<< path.points[ segment_data::point::control2 ].x << ' '
<< path.points[ segment_data::point::control2 ].y << ' '
<< path.points[ segment_data::point::control2 ].z << ' '
<< path.points[ segment_data::point::end ].x << ' '
<< path.points[ segment_data::point::end ].y << ' '
<< path.points[ segment_data::point::end ].z << ' '
<< path.rolls[ 1 ] << ' '
<< path.radius << ' ';
}
// optional attributes
if( false == asEvent0Name.empty() ) {
Output << "event0 " << asEvent0Name << ' ';
}
if( false == asEvent1Name.empty() ) {
Output << "event1 " << asEvent1Name << ' ';
}
if( false == asEvent2Name.empty() ) {
Output << "event2 " << asEvent2Name << ' ';
}
if( false == asEventall0Name.empty() ) {
Output << "eventall0 " << asEventall0Name << ' ';
}
if( false == asEventall1Name.empty() ) {
Output << "eventall1 " << asEventall1Name << ' ';
}
if( false == asEventall2Name.empty() ) {
Output << "eventall2 " << asEventall2Name << ' ';
}
if( ( SwitchExtension )
&& ( SwitchExtension->fVelocity != -1.0 ) ) {
Output << "velocity " << SwitchExtension->fVelocity << ' ';
}
else {
if( fVelocity != -1.0 ) {
Output << "velocity " << fVelocity << ' ';
}
}
if( pIsolated ) {
Output << "isolated " << pIsolated->asName << ' ';
}
if( fOverhead != -1.0 ) {
Output << "overhead " << fOverhead << ' ';
}
// footer
Output
<< "endtrack"
<< "\n";
} }
void TTrack::MovedUp1(float const dh) void TTrack::MovedUp1(float const dh)
{ // poprawienie przechyłki wymaga wydłużenia podsypki { // poprawienie przechyłki wymaga wydłużenia podsypki
fTexHeight1 += dh; fTexHeight1 += dh;
fTexHeightOffset += dh;
}; };
void TTrack::VelocitySet(float v) // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii) void TTrack::VelocitySet(float v) {
if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false) // TBD, TODO: add a variable to preserve potential speed limit set by the track configuration on basic track pieces
{ // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem if( ( SwitchExtension )
if (v > SwitchExtension->fVelocity ? true : v < 0.0) && ( SwitchExtension->fVelocity != -1 ) ) {
return void(fVelocity = // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
SwitchExtension->fVelocity); // maksymalnie tyle, ile było we wpisie fVelocity =
min_speed<float>(
v,
( SwitchExtension->fVelocity > 0 ?
SwitchExtension->fVelocity : // positive limit applies to both switch tracks
( SwitchExtension->CurrentIndex == 0 ?
-1 : // negative limit applies only to the diverging track
-SwitchExtension->fVelocity ) ) );
} }
else {
fVelocity = v; // nie ma ograniczenia fVelocity = v; // nie ma ograniczenia
}
}; };
double TTrack::VelocityGet() double TTrack::VelocityGet()
@@ -2800,11 +3081,13 @@ path_table::InitTracks() {
track->AssignEvents( track->AssignEvents(
simulation::Events.FindEvent( trackname + ":event0" ), simulation::Events.FindEvent( trackname + ":event0" ),
simulation::Events.FindEvent( trackname + ":event1" ), simulation::Events.FindEvent( trackname + ":event1" ),
simulation::Events.FindEvent( trackname + ":event2" ) ); simulation::Events.FindEvent( trackname + ":event2" ),
false );
track->AssignallEvents( track->AssignallEvents(
simulation::Events.FindEvent( trackname + ":eventall0" ), simulation::Events.FindEvent( trackname + ":eventall0" ),
simulation::Events.FindEvent( trackname + ":eventall1" ), simulation::Events.FindEvent( trackname + ":eventall1" ),
simulation::Events.FindEvent( trackname + ":eventall2" ) ); simulation::Events.FindEvent( trackname + ":eventall2" ),
false );
} }
switch (track->eType) { switch (track->eType) {
@@ -2948,6 +3231,8 @@ path_table::InitTracks() {
scene::node_data nodedata; scene::node_data nodedata;
nodedata.name = isolated->asName; nodedata.name = isolated->asName;
auto *memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy auto *memorycell = new TMemCell( nodedata ); // to nie musi mieć nazwy, nazwa w wyszukiwarce wystarczy
// NOTE: autogenerated cells aren't exported; they'll be autogenerated anew when exported file is loaded
memorycell->is_exportable = false;
simulation::Memory.insert( memorycell ); simulation::Memory.insert( memorycell );
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
} }

23
Track.h
View File

@@ -124,7 +124,7 @@ private:
}; };
// trajektoria ruchu - opakowanie // trajektoria ruchu - opakowanie
class TTrack : public editor::basic_node { class TTrack : public scene::basic_node {
friend class opengl_renderer; friend class opengl_renderer;
@@ -142,6 +142,7 @@ private:
float fTexRatio1 = 1.0f; // proporcja boków tekstury nawierzchni (żeby zaoszczędzić na rozmiarach tekstur...) 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...) float fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
float fTexHeight1 = 0.6f; // wysokość brzegu względem trajektorii float fTexHeight1 = 0.6f; // wysokość brzegu względem trajektorii
float fTexHeightOffset = 0.f; // potential adjustment to account for the path roll
float fTexWidth = 0.9f; // szerokość boku float fTexWidth = 0.9f; // szerokość boku
float fTexSlope = 0.9f; float fTexSlope = 0.9f;
@@ -152,6 +153,8 @@ private:
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1 geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2 geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
std::vector<segment_data> m_paths; // source data for owned paths
public: public:
typedef std::deque<TDynamicObject *> dynamics_sequence; typedef std::deque<TDynamicObject *> dynamics_sequence;
dynamics_sequence Dynamics; dynamics_sequence Dynamics;
@@ -231,8 +234,8 @@ public:
SwitchExtension->iRoads - 1 : SwitchExtension->iRoads - 1 :
1 ); } 1 ); }
void Load(cParser *parser, Math3D::vector3 pOrigin); void Load(cParser *parser, Math3D::vector3 pOrigin);
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit = true );
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2); bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit = true );
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus); bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
bool CheckDynamicObject(TDynamicObject *Dynamic); bool CheckDynamicObject(TDynamicObject *Dynamic);
bool AddDynamicObject(TDynamicObject *Dynamic); bool AddDynamicObject(TDynamicObject *Dynamic);
@@ -270,10 +273,16 @@ public:
double VelocityGet(); double VelocityGet();
void ConnectionsLog(); void ConnectionsLog();
protected: private:
// calculates path's bounding radius // radius() subclass details, calculates node's bounding radius
void float radius_();
radius_(); // serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
}; };

View File

@@ -529,18 +529,6 @@ double TTraction::VoltageGet(double u, double i)
return 0.0; // gdy nie podłączony wcale? return 0.0; // gdy nie podłączony wcale?
}; };
// calculates path's bounding radius
void
TTraction::radius_() {
auto const points = endpoints();
for( auto &point : points ) {
m_area.radius = std::max(
m_area.radius,
static_cast<float>( glm::length( m_area.center - point ) ) );
}
}
glm::vec3 glm::vec3
TTraction::wire_color() const { TTraction::wire_color() const {
@@ -580,6 +568,7 @@ TTraction::wire_color() const {
color.r *= Global.DayLight.ambient[ 0 ]; color.r *= Global.DayLight.ambient[ 0 ];
color.g *= Global.DayLight.ambient[ 1 ]; color.g *= Global.DayLight.ambient[ 1 ];
color.b *= Global.DayLight.ambient[ 2 ]; color.b *= Global.DayLight.ambient[ 2 ];
color *= 0.5f;
} }
else { else {
// tymczasowo pokazanie zasilanych odcinków // tymczasowo pokazanie zasilanych odcinków
@@ -675,6 +664,77 @@ TTraction::wire_color() const {
return color; return color;
} }
// radius() subclass details, calculates node's bounding radius
float
TTraction::radius_() {
auto const points { endpoints() };
auto radius { 0.f };
for( auto &point : points ) {
radius = std::max(
radius,
static_cast<float>( glm::length( m_area.center - point ) ) );
}
return radius;
}
// serialize() subclass details, sends content of the subclass to provided stream
void
TTraction::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TTraction::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TTraction::export_as_text_( std::ostream &Output ) const {
// header
Output << "traction ";
// basic attributes
Output
<< asPowerSupplyName << ' '
<< NominalVoltage << ' '
<< MaxCurrent << ' '
<< ( fResistivity * 1000 ) << ' '
<< (
Material == 2 ? "al" :
Material == 0 ? "none" :
"cu" ) << ' '
<< WireThickness << ' '
<< DamageFlag << ' ';
// path data
Output
<< pPoint1.x << ' ' << pPoint1.y << ' ' << pPoint1.z << ' '
<< pPoint2.x << ' ' << pPoint2.y << ' ' << pPoint2.z << ' '
<< pPoint3.x << ' ' << pPoint3.y << ' ' << pPoint3.z << ' '
<< pPoint4.x << ' ' << pPoint4.y << ' ' << pPoint4.z << ' ';
// minimum height
Output << ( ( pPoint3.y - pPoint1.y + pPoint4.y - pPoint2.y ) * 0.5 - fHeightDifference ) << ' ';
// segment length
Output << static_cast<int>( iNumSections ? glm::length( pPoint1 - pPoint2 ) / iNumSections : 0.0 ) << ' ';
// wire data
Output
<< Wires << ' '
<< WireOffset << ' ';
// visibility
// NOTE: 'invis' would be less wrong than 'unvis', but potentially incompatible with old 3rd party tools
Output << ( m_visible ? "vis" : "unvis" ) << ' ';
// optional attributes
if( false == asParallel.empty() ) {
Output << "parallel " << asParallel << ' ';
}
// footer
Output
<< "endtraction"
<< "\n";
}
// legacy method, initializes traction after deserialization from scenario file // legacy method, initializes traction after deserialization from scenario file

View File

@@ -18,7 +18,7 @@ http://mozilla.org/MPL/2.0/.
class TTractionPowerSource; class TTractionPowerSource;
class TTraction : public editor::basic_node { class TTraction : public scene::basic_node {
friend class opengl_renderer; friend class opengl_renderer;
@@ -73,13 +73,18 @@ class TTraction : public editor::basic_node {
void PowerSet(TTractionPowerSource *ps); void PowerSet(TTractionPowerSource *ps);
double VoltageGet(double u, double i); double VoltageGet(double u, double i);
protected:
// calculates piece's bounding radius
void
radius_();
private: private:
// methods
glm::vec3 wire_color() const; glm::vec3 wire_color() const;
// radius() subclass details, calculates node's bounding radius
float radius_();
// serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
}; };

View File

@@ -141,6 +141,52 @@ void TTractionPowerSource::PowerSet(TTractionPowerSource *ps)
// else ErrorLog("nie może być więcej punktów zasilania niż dwa"); // else ErrorLog("nie może być więcej punktów zasilania niż dwa");
}; };
// serialize() subclass details, sends content of the subclass to provided stream
void
TTractionPowerSource::serialize_( std::ostream &Output ) const {
// TODO: implement
}
// deserialize() subclass details, restores content of the subclass from provided stream
void
TTractionPowerSource::deserialize_( std::istream &Input ) {
// TODO: implement
}
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void
TTractionPowerSource::export_as_text_( std::ostream &Output ) const {
// header
Output << "tractionpowersource ";
// placement
Output
<< location().x << ' '
<< location().y << ' '
<< location().z << ' ';
// basic attributes
Output
<< NominalVoltage << ' '
<< VoltageFrequency << ' '
<< InternalRes << ' '
<< MaxOutputCurrent << ' '
<< FastFuseTimeOut << ' '
<< FastFuseRepetition << ' '
<< SlowFuseTimeOut << ' ';
// optional attributes
if( true == Recuperation ) {
Output << "recuperation ";
}
if( true == bSection ) {
Output << "section ";
}
// footer
Output
<< "end"
<< "\n";
}
// legacy method, calculates changes in simulation state over specified time // legacy method, calculates changes in simulation state over specified time

View File

@@ -13,9 +13,33 @@ http://mozilla.org/MPL/2.0/.
#include "scenenode.h" #include "scenenode.h"
#include "names.h" #include "names.h"
class TTractionPowerSource : public editor::basic_node { class TTractionPowerSource : public scene::basic_node {
private: public:
// constructor
TTractionPowerSource( scene::node_data const &Nodedata );
// methods
void Init(double const u, double const i);
bool Load(cParser *parser);
bool Update(double dt);
double CurrentGet(double res);
void VoltageSet(double const v) {
NominalVoltage = v; };
void PowerSet(TTractionPowerSource *ps);
// members
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
bool bSection = false; // czy jest sekcją
private:
// methods
// serialize() subclass details, sends content of the subclass to provided stream
void serialize_( std::ostream &Output ) const;
// deserialize() subclass details, restores content of the subclass from provided stream
void deserialize_( std::istream &Input );
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
void export_as_text_( std::ostream &Output ) const;
// members
double NominalVoltage = 0.0; double NominalVoltage = 0.0;
double VoltageFrequency = 0.0; double VoltageFrequency = 0.0;
double InternalRes = 0.2; double InternalRes = 0.2;
@@ -34,20 +58,6 @@ class TTractionPowerSource : public editor::basic_node {
double FuseTimer = 0.0; double FuseTimer = 0.0;
int FuseCounter = 0; int FuseCounter = 0;
public:
// zmienne publiczne
TTractionPowerSource *psNode[ 2 ] = { nullptr, nullptr }; // zasilanie na końcach dla sekcji
bool bSection = false; // czy jest sekcją
TTractionPowerSource( scene::node_data const &Nodedata );
void Init(double const u, double const i);
bool Load(cParser *parser);
bool Update(double dt);
double CurrentGet(double res);
void VoltageSet(double const v) {
NominalVoltage = v; };
void PowerSet(TTractionPowerSource *ps);
}; };

View File

@@ -311,7 +311,6 @@ bool TWorld::Init( GLFWwindow *Window ) {
void TWorld::OnKeyDown(int cKey) { void TWorld::OnKeyDown(int cKey) {
// dump keypress info in the log // dump keypress info in the log
if( !Global.iPause ) {
// podczas pauzy klawisze nie działają // podczas pauzy klawisze nie działają
std::string keyinfo; std::string keyinfo;
auto keyname = glfwGetKeyName( cKey, 0 ); auto keyname = glfwGetKeyName( cKey, 0 );
@@ -354,7 +353,6 @@ void TWorld::OnKeyDown(int cKey) {
WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" ); WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" );
} }
}
// actual key processing // actual key processing
// TODO: redo the input system // TODO: redo the input system
@@ -504,6 +502,14 @@ void TWorld::OnKeyDown(int cKey) {
} }
break; break;
} }
case GLFW_KEY_F11: {
// scenery export
if( Global.ctrlState
&& Global.shiftState ) {
simulation::State.export_as_text( Global.SceneryFile );
}
break;
}
case GLFW_KEY_F12: { case GLFW_KEY_F12: {
// quick debug mode toggle // quick debug mode toggle
if( Global.ctrlState if( Global.ctrlState

View File

@@ -228,6 +228,17 @@ basic_cell::deserialize( std::istream &Input ) {
|| ( false == m_lines.empty() ) ); || ( false == m_lines.empty() ) );
} }
// sends content of the class in legacy (text) format to provided stream
void
basic_cell::export_as_text( std::ostream &Output ) const {
// text format export dumps only relevant basic objects
// sounds
for( auto const *sound : m_sounds ) {
sound->export_as_text( Output );
}
}
// adds provided shape to the cell // adds provided shape to the cell
void void
basic_cell::insert( shape_node Shape ) { basic_cell::insert( shape_node Shape ) {
@@ -530,7 +541,7 @@ basic_cell::create_geometry( gfx::geometrybank_handle const &Bank ) {
// adjusts cell bounding area to enclose specified node // adjusts cell bounding area to enclose specified node
void void
basic_cell::enclose_area( editor::basic_node *Node ) { basic_cell::enclose_area( scene::basic_node *Node ) {
m_area.radius = std::max( m_area.radius = std::max(
m_area.radius, m_area.radius,
@@ -645,6 +656,16 @@ basic_section::deserialize( std::istream &Input ) {
} }
} }
// sends content of the class in legacy (text) format to provided stream
void
basic_section::export_as_text( std::ostream &Output ) const {
// text format export dumps only relevant basic objects from non-empty cells
for( auto const &cell : m_cells ) {
cell.export_as_text( Output );
}
}
// adds provided shape to the section // adds provided shape to the section
void void
basic_section::insert( shape_node Shape ) { basic_section::insert( shape_node Shape ) {
@@ -949,6 +970,18 @@ basic_region::deserialize( std::string const &Scenariofile ) {
return true; return true;
} }
// sends content of the class in legacy (text) format to provided stream
void
basic_region::export_as_text( std::ostream &Output ) const {
for( auto *section : m_sections ) {
// text format export dumps only relevant basic objects from non-empty sections
if( section != nullptr ) {
section->export_as_text( Output );
}
}
}
// legacy method, links specified path piece with potential neighbours // legacy method, links specified path piece with potential neighbours
void void
basic_region::TrackJoin( TTrack *Track ) { basic_region::TrackJoin( TTrack *Track ) {

11
scene.h
View File

@@ -88,6 +88,9 @@ public:
// restores content of the class from provided stream // restores content of the class from provided stream
void void
deserialize( std::istream &Input ); deserialize( std::istream &Input );
// sends content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
// adds provided shape to the cell // adds provided shape to the cell
void void
insert( shape_node Shape ); insert( shape_node Shape );
@@ -149,7 +152,7 @@ private:
using eventlauncher_sequence = std::vector<TEventLauncher *>; using eventlauncher_sequence = std::vector<TEventLauncher *>;
// methods // methods
void void
enclose_area( editor::basic_node *Node ); enclose_area( scene::basic_node *Node );
// members // members
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) }; scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) };
bool m_active { false }; // whether the cell holds any actual data bool m_active { false }; // whether the cell holds any actual data
@@ -199,6 +202,9 @@ public:
// restores content of the class from provided stream // restores content of the class from provided stream
void void
deserialize( std::istream &Input ); deserialize( std::istream &Input );
// sends content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
// adds provided shape to the section // adds provided shape to the section
void void
insert( shape_node Shape ); insert( shape_node Shape );
@@ -289,6 +295,9 @@ public:
// restores content of the class from file with specified name. returns: true on success, false otherwise // restores content of the class from file with specified name. returns: true on success, false otherwise
bool bool
deserialize( std::string const &Scenariofile ); deserialize( std::string const &Scenariofile );
// sends content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
// legacy method, links specified path piece with potential neighbours // legacy method, links specified path piece with potential neighbours
void void
TrackJoin( TTrack *Track ); TrackJoin( TTrack *Track );

View File

@@ -142,7 +142,7 @@ shape_node::deserialize( std::istream &Input ) {
// restores content of the node from provided input stream // restores content of the node from provided input stream
shape_node & shape_node &
shape_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) { shape_node::import( cParser &Input, scene::node_data const &Nodedata ) {
// import common data // import common data
m_name = Nodedata.name; m_name = Nodedata.name;
@@ -523,7 +523,7 @@ lines_node::deserialize( std::istream &Input ) {
// restores content of the node from provded input stream // restores content of the node from provded input stream
lines_node & lines_node &
lines_node::deserialize( cParser &Input, scene::node_data const &Nodedata ) { lines_node::import( cParser &Input, scene::node_data const &Nodedata ) {
// import common data // import common data
m_name = Nodedata.name; m_name = Nodedata.name;
@@ -684,12 +684,9 @@ memory_node::deserialize( cParser &Input, node_data const &Nodedata ) {
memorycell.Load( &Input ); memorycell.Load( &Input );
} }
*/ */
} // scene
namespace editor {
basic_node::basic_node( scene::node_data const &Nodedata ) : basic_node::basic_node( scene::node_data const &Nodedata ) :
m_name( Nodedata.name ) m_name( Nodedata.name )
{ {
@@ -700,23 +697,69 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
std::numeric_limits<double>::max() ); std::numeric_limits<double>::max() );
} }
// sends content of the class to provided stream
void
basic_node::serialize( std::ostream &Output ) const {
// bounding area
m_area.serialize( Output );
// visibility
sn_utils::ls_float64( Output, m_rangesquaredmin );
sn_utils::ls_float64( Output, m_rangesquaredmax );
sn_utils::s_bool( Output, m_visible );
// name
sn_utils::s_str( Output, m_name );
// template method implementation
serialize_( Output );
}
// restores content of the class from provided stream
void
basic_node::deserialize( std::istream &Input ) {
// bounding area
m_area.deserialize( Input );
// visibility
m_rangesquaredmin = sn_utils::ld_float64( Input );
m_rangesquaredmax = sn_utils::ld_float64( Input );
m_visible = sn_utils::d_bool( Input );
// name
m_name = sn_utils::d_str( Input );
// template method implementation
deserialize_( Input );
}
// sends basic content of the class in legacy (text) format to provided stream
void
basic_node::export_as_text( std::ostream &Output ) const {
Output
// header
<< "node"
// visibility
<< ' ' << ( m_rangesquaredmax < std::numeric_limits<double>::max() ? std::sqrt( m_rangesquaredmax ) : -1 )
<< ' ' << std::sqrt( m_rangesquaredmin )
// name
<< ' ' << m_name << ' ';
// template method implementation
export_as_text_( Output );
}
float const & float const &
basic_node::radius() { basic_node::radius() {
if( m_area.radius == -1.0 ) { if( m_area.radius == -1.0 ) {
// calculate if needed // calculate if needed
radius_(); m_area.radius = radius_();
} }
return m_area.radius; return m_area.radius;
} }
// radius() subclass details, calculates node's bounding radius // radius() subclass details, calculates node's bounding radius
// by default nodes are 'virtual don't extend from their center point // by default nodes are 'virtual don't extend from their center point
void float
basic_node::radius_() { basic_node::radius_() {
m_area.radius = 0.f; return 0.f;
} }
} // editor } // scene
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -112,7 +112,7 @@ public:
deserialize( std::istream &Input ); deserialize( std::istream &Input );
// restores content of the node from provided input stream // restores content of the node from provided input stream
shape_node & shape_node &
deserialize( cParser &Input, scene::node_data const &Nodedata ); import( cParser &Input, scene::node_data const &Nodedata );
// imports data from provided submodel // imports data from provided submodel
shape_node & shape_node &
convert( TSubModel const *Submodel ); convert( TSubModel const *Submodel );
@@ -201,7 +201,7 @@ public:
deserialize( std::istream &Input ); deserialize( std::istream &Input );
// restores content of the node from provided input stream // restores content of the node from provided input stream
lines_node & lines_node &
deserialize( cParser &Input, scene::node_data const &Nodedata ); import( cParser &Input, scene::node_data const &Nodedata );
// adds content of provided node to already enclosed geometry. returns: true if merge could be performed // adds content of provided node to already enclosed geometry. returns: true if merge could be performed
bool bool
merge( lines_node &Lines ); merge( lines_node &Lines );
@@ -295,12 +295,9 @@ private:
TTrack * m_path; TTrack * m_path;
}; };
*/ */
} // scene
namespace editor {
// base interface for nodes which can be actvated in scenario editor // base interface for nodes which can be actvated in scenario editor
struct basic_node { struct basic_node {
@@ -310,6 +307,15 @@ public:
// destructor // destructor
virtual ~basic_node() = default; virtual ~basic_node() = default;
// methods // methods
// sends content of the class to provided stream
void
serialize( std::ostream &Output ) const;
// restores content of the class from provided stream
void
deserialize( std::istream &Input );
// sends basic content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
std::string const & std::string const &
name() const; name() const;
void void
@@ -324,15 +330,23 @@ public:
visible() const; visible() const;
protected: protected:
// methods
// radius() subclass details, calculates node's bounding radius
virtual void radius_();
// members // members
scene::bounding_area m_area; scene::bounding_area m_area;
bool m_visible { true };
double m_rangesquaredmin { 0.0 }; // visibility range, min double m_rangesquaredmin { 0.0 }; // visibility range, min
double m_rangesquaredmax { 0.0 }; // visibility range, max double m_rangesquaredmax { 0.0 }; // visibility range, max
bool m_visible { true }; // visibility flag
std::string m_name; std::string m_name;
private:
// methods
// radius() subclass details, calculates node's bounding radius
virtual float radius_();
// serialize() subclass details, sends content of the subclass to provided stream
virtual void serialize_( std::ostream &Output ) const = 0;
// deserialize() subclass details, restores content of the subclass from provided stream
virtual void deserialize_( std::istream &Input ) = 0;
// export() subclass details, sends basic content of the class in legacy (text) format to provided stream
virtual void export_as_text_( std::ostream &Output ) const = 0;
}; };
inline inline
@@ -365,6 +379,6 @@ basic_node::visible() const {
return m_visible; return m_visible;
} }
} // editor } // scene
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
#include "uilayer.h" #include "uilayer.h"
#include "renderer.h" #include "renderer.h"
namespace simulation { namespace simulation {
state_manager State; state_manager State;
@@ -57,8 +58,6 @@ state_manager::deserialize( std::string const &Scenariofile ) {
// as long as the scenario file wasn't rainsted-created base file override // as long as the scenario file wasn't rainsted-created base file override
Region->serialize( Scenariofile ); Region->serialize( Scenariofile );
} }
Global.iPause &= ~0x10; // koniec pauzy wczytywania
return true; return true;
} }
@@ -409,7 +408,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
if( false == Scratchpad.binary.terrain ) { if( false == Scratchpad.binary.terrain ) {
simulation::Region->insert_shape( simulation::Region->insert_shape(
scene::shape_node().deserialize( scene::shape_node().import(
Input, nodedata ), Input, nodedata ),
Scratchpad, Scratchpad,
true ); true );
@@ -426,7 +425,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
if( false == Scratchpad.binary.terrain ) { if( false == Scratchpad.binary.terrain ) {
simulation::Region->insert_lines( simulation::Region->insert_lines(
scene::lines_node().deserialize( scene::lines_node().import(
Input, nodedata ), Input, nodedata ),
Scratchpad ); Scratchpad );
} }
@@ -439,7 +438,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) }; auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
if( false == simulation::Memory.insert( memorycell ) ) { if( false == simulation::Memory.insert( memorycell ) ) {
ErrorLog( "Bad scenario: memory cell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" ); ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
} }
/* /*
// TODO: implement this // TODO: implement this
@@ -897,6 +896,65 @@ state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratc
return Location; return Location;
} }
// stores class data in specified file, in legacy (text) format
void
state_manager::export_as_text( std::string const &Scenariofile ) const {
if( Scenariofile == "$.scn" ) {
ErrorLog( "Bad file: scenery export not supported for file \"$.scn\"" );
}
else {
WriteLog( "Scenery data export in progress..." );
}
auto filename { Scenariofile };
while( filename[ 0 ] == '$' ) {
// trim leading $ char rainsted utility may add to the base name for modified .scn files
filename.erase( 0, 1 );
}
erase_extension( filename );
filename = Global.asCurrentSceneryPath + filename + "_export";
std::ofstream scmfile { filename + ".scm" };
// tracks
scmfile << "// paths\n";
for( auto const *path : Paths.sequence() ) {
path->export_as_text( scmfile );
}
// traction
scmfile << "// traction\n";
for( auto const *traction : Traction.sequence() ) {
traction->export_as_text( scmfile );
}
// power grid
scmfile << "// traction power sources\n";
for( auto const *powersource : Powergrid.sequence() ) {
powersource->export_as_text( scmfile );
}
// models
scmfile << "// instanced models\n";
for( auto const *instance : Instances.sequence() ) {
instance->export_as_text( scmfile );
}
// sounds
scmfile << "// sounds\n";
Region->export_as_text( scmfile );
std::ofstream ctrfile { filename + ".ctr" };
// mem cells
ctrfile << "// memory cells\n";
for( auto const *memorycell : Memory.sequence() ) {
if( true == memorycell->is_exportable ) {
memorycell->export_as_text( ctrfile );
}
}
// events
Events.export_as_text( ctrfile );
WriteLog( "Scenery data export done." );
}
} // simulation } // simulation
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -36,6 +36,9 @@ public:
update( double Deltatime, int Iterationcount ); update( double Deltatime, int Iterationcount );
bool bool
deserialize( std::string const &Scenariofile ); deserialize( std::string const &Scenariofile );
// stores class data in specified file, in legacy (text) format
void
export_as_text( std::string const &Scenariofile ) const;
private: private:
// methods // methods
@@ -69,6 +72,7 @@ private:
void skip_until( cParser &Input, std::string const &Token ); void skip_until( cParser &Input, std::string const &Token );
// transforms provided location by specifed rotation and offset // transforms provided location by specifed rotation and offset
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ); glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
}; };
extern state_manager State; extern state_manager State;

View File

@@ -293,6 +293,43 @@ sound_source::deserialize_soundset( cParser &Input ) {
} }
} }
// sends content of the class in legacy (text) format to provided stream
// NOTE: currently exports only the main sound
void
sound_source::export_as_text( std::ostream &Output ) const {
if( sound( sound_id::main ).buffer == null_handle ) { return; }
// generic node header
Output
<< "node "
// visibility
<< m_range << ' '
<< 0 << ' '
// name
<< m_name << ' ';
// sound node header
Output
<< "sound ";
// location
Output
<< m_offset.x << ' '
<< m_offset.y << ' '
<< m_offset.z << ' ';
// sound data
auto soundfile { audio::renderer.buffer( sound( sound_id::main ).buffer ).name };
if( soundfile.find( szSoundPath ) == 0 ) {
// don't include 'sounds/' in the path
soundfile.erase( 0, std::string{ szSoundPath }.size() );
}
Output
<< soundfile << ' ';
// footer
Output
<< "endsound"
<< "\n";
}
// copies list of sounds from provided source // copies list of sounds from provided source
sound_source & sound_source &
sound_source::copy_sounds( sound_source const &Source ) { sound_source::copy_sounds( sound_source const &Source ) {

View File

@@ -60,6 +60,9 @@ public:
deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 ); deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 );
sound_source & sound_source &
deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = 0 ); deserialize( std::string const &Input, sound_type const Legacytype, int const Legacyparameters = 0 );
// sends content of the class in legacy (text) format to provided stream
void
export_as_text( std::ostream &Output ) const;
// copies list of sounds from provided source // copies list of sounds from provided source
sound_source & sound_source &
copy_sounds( sound_source const &Source ); copy_sounds( sound_source const &Source );

View File

@@ -98,6 +98,7 @@ ui_layer::on_key( int const Key, int const Action ) {
case GLFW_KEY_F8: case GLFW_KEY_F8:
case GLFW_KEY_F9: case GLFW_KEY_F9:
case GLFW_KEY_F10: case GLFW_KEY_F10:
case GLFW_KEY_F11:
case GLFW_KEY_F12: { // ui mode selectors case GLFW_KEY_F12: { // ui mode selectors
if( ( true == Global.ctrlState ) if( ( true == Global.ctrlState )