mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
basic scenery data export in legacy text format
This commit is contained in:
112
AnimModel.cpp
112
AnimModel.cpp
@@ -423,13 +423,6 @@ TAnimModel::~TAnimModel()
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else{
|
||||
// tekstura nieprzezroczysta - nie renderować w cyklu
|
||||
// tekstura nieprzezroczysta - nie renderować w cyklu przezroczystych
|
||||
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)
|
||||
{ // rozpoznanie wpisu modelu i ustawienie świateł
|
||||
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 (name != "notload")
|
||||
@@ -504,7 +501,7 @@ bool TAnimModel::Load(cParser *parser, bool ter)
|
||||
while( ( token != "" )
|
||||
&& ( 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;
|
||||
|
||||
token = "";
|
||||
@@ -563,15 +560,6 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
|
||||
m_framestamp = Framestamp;
|
||||
};
|
||||
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
TAnimModel::radius_() {
|
||||
|
||||
if( pModel != nullptr ) {
|
||||
m_area.radius = pModel->bounding_radius();
|
||||
}
|
||||
}
|
||||
|
||||
void TAnimModel::RaPrepare()
|
||||
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
|
||||
bool state; // stan światła
|
||||
@@ -584,7 +572,11 @@ void TAnimModel::RaPrepare()
|
||||
state = ( fBlinkTimer < fOnTime );
|
||||
break;
|
||||
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;
|
||||
default: // zapalony albo zgaszony
|
||||
state = (lightmode == ls_On);
|
||||
@@ -780,15 +772,17 @@ void TAnimModel::LightSet(int const n, float const v)
|
||||
}
|
||||
case ls_Dark: {
|
||||
// zapalenie świateł zależne od oświetlenia scenerii
|
||||
if( v == 3.0 ) {
|
||||
/*
|
||||
if( v == 3.f ) {
|
||||
// standardowy próg zaplania
|
||||
lsLights[ n ] = 3.0 + DefaultDarkThresholdLevel;
|
||||
lsLights[ n ] = 3.f + DefaultDarkThresholdLevel;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void TAnimModel::AnimUpdate(double dt)
|
||||
{ // wykonanie zakolejkowanych animacji, nawet gdy modele nie są aktualnie wyświetlane
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
// 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";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
21
AnimModel.h
21
AnimModel.h
@@ -122,7 +122,7 @@ class TAnimAdvanced
|
||||
};
|
||||
|
||||
// opakowanie modelu, określające stan egzemplarza
|
||||
class TAnimModel : public editor::basic_node {
|
||||
class TAnimModel : public scene::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -133,15 +133,12 @@ public:
|
||||
~TAnimModel();
|
||||
// methods
|
||||
static void AnimUpdate( double dt );
|
||||
bool Init(TModel3d *pNewModel);
|
||||
bool Init(std::string const &asName, std::string const &asReplacableTexture);
|
||||
bool Load(cParser *parser, bool ter = false);
|
||||
TAnimContainer * AddContainer(std::string const &Name);
|
||||
TAnimContainer * GetContainer(std::string const &Name = "");
|
||||
void RaAnglesSet( glm::vec3 Angles ) {
|
||||
vAngle.x = Angles.x;
|
||||
vAngle.y = Angles.y;
|
||||
vAngle.z = Angles.z; };
|
||||
vAngle = { Angles }; };
|
||||
void LightSet( int const n, float const v );
|
||||
void AnimationVND( void *pData, double a, double b, double c, double d );
|
||||
bool TerrainLoaded();
|
||||
@@ -159,16 +156,20 @@ public:
|
||||
// members
|
||||
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu
|
||||
void RaAnimate( unsigned int const Framestamp ); // przeliczenie animacji egzemplarza
|
||||
void Advanced();
|
||||
// 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
|
||||
TAnimContainer *pRoot { nullptr }; // pojemniki sterujące, tylko dla aniomowanych submodeli
|
||||
TModel3d *pModel { nullptr };
|
||||
|
||||
85
EvLaunch.cpp
85
EvLaunch.cpp
@@ -194,11 +194,90 @@ bool TEventLauncher::IsGlobal() const {
|
||||
&& ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
|
||||
}
|
||||
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
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";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
17
EvLaunch.h
17
EvLaunch.h
@@ -14,7 +14,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Classes.h"
|
||||
#include "scenenode.h"
|
||||
|
||||
class TEventLauncher : public editor::basic_node {
|
||||
class TEventLauncher : public scene::basic_node {
|
||||
|
||||
public:
|
||||
// constructor
|
||||
@@ -37,12 +37,17 @@ public:
|
||||
int iCheckMask { 0 };
|
||||
double dRadius { 0.0 };
|
||||
|
||||
protected:
|
||||
// calculates node's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
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
|
||||
int iKey { 0 };
|
||||
double DeltaTime { -1.0 };
|
||||
|
||||
244
Event.cpp
244
Event.cpp
@@ -304,9 +304,9 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
if (token.find('#') != std::string::npos)
|
||||
token.erase(token.find('#')); // obcięcie unikatowości
|
||||
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;
|
||||
// nie do kolejki (dla SetVelocity też, ale jak jest do toru dowiązany)
|
||||
bEnabled = false;
|
||||
}
|
||||
else if (token == "SetVelocity")
|
||||
{
|
||||
@@ -328,11 +328,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
bEnabled = false;
|
||||
Params[6].asCommand = cm_ShuntVelocity;
|
||||
}
|
||||
//else if (str == "SetProximityVelocity")
|
||||
//{
|
||||
// bEnabled = false;
|
||||
// Params[6].asCommand = cm_SetProximityVelocity;
|
||||
//}
|
||||
else if (token == "OutsideStation")
|
||||
{
|
||||
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( paramidx < 8 ) {
|
||||
// HACK: mark unspecified lights with magic value
|
||||
Params[ paramidx ].asdouble = -2.0;
|
||||
++paramidx;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_Visible: // zmiana wyświetlania obiektu
|
||||
@@ -403,7 +403,7 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
case tp_Velocity:
|
||||
parser->getTokens();
|
||||
*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 >> token;
|
||||
break;
|
||||
@@ -420,7 +420,6 @@ void TEvent::Load(cParser *parser, Math3D::vector3 const &org)
|
||||
*parser >> token;
|
||||
break;
|
||||
case tp_Exit:
|
||||
asNodeName = ExchangeCharInString( asNodeName, '_', ' ' );
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
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 ) {
|
||||
|
||||
TEvent *target( Start );
|
||||
@@ -1002,6 +1186,10 @@ event_manager::CheckQuery() {
|
||||
case tp_Lights: {
|
||||
if( m_workevent->Params[ 9 ].asModel ) {
|
||||
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 ) {
|
||||
// -1 zostawia bez zmiany
|
||||
m_workevent->Params[ 9 ].asModel->LightSet(
|
||||
@@ -1013,8 +1201,8 @@ event_manager::CheckQuery() {
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
if( m_workevent->Params[ 9 ].asEditorNode )
|
||||
m_workevent->Params[ 9 ].asEditorNode->visible( m_workevent->Params[ 0 ].asInt > 0 );
|
||||
if( m_workevent->Params[ 9 ].asSceneNode )
|
||||
m_workevent->Params[ 9 ].asSceneNode->visible( m_workevent->Params[ 0 ].asInt > 0 );
|
||||
break;
|
||||
}
|
||||
case tp_Velocity: {
|
||||
@@ -1022,8 +1210,12 @@ event_manager::CheckQuery() {
|
||||
break;
|
||||
}
|
||||
case tp_Exit: {
|
||||
MessageBox( 0, m_workevent->asNodeName.c_str(), " THE END ", MB_OK );
|
||||
Global.iTextMode = -1; // wyłączenie takie samo jak sekwencja F10 -> Y
|
||||
// wyłączenie takie samo jak sekwencja F10 -> Y
|
||||
MessageBox(
|
||||
0,
|
||||
ExchangeCharInString( m_workevent->asNodeName, '_', ' ' ).c_str(),
|
||||
" THE END ",
|
||||
MB_OK );
|
||||
return false;
|
||||
}
|
||||
case tp_Sound: {
|
||||
@@ -1404,7 +1596,6 @@ event_manager::InitEvents() {
|
||||
else {
|
||||
ErrorLog( "Bad event: animation event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Lights: {
|
||||
@@ -1414,12 +1605,11 @@ event_manager::InitEvents() {
|
||||
event->Params[ 9 ].asModel = instance;
|
||||
else
|
||||
ErrorLog( "Bad event: lights event \"" + event->asName + "\" cannot find model instance \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Visible: {
|
||||
// ukrycie albo przywrócenie obiektu
|
||||
editor::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
|
||||
scene::basic_node *node = simulation::Instances.find( event->asNodeName ); // najpierw model
|
||||
if( node == nullptr ) {
|
||||
// albo tory?
|
||||
node = simulation::Paths.find( event->asNodeName );
|
||||
@@ -1429,12 +1619,11 @@ event_manager::InitEvents() {
|
||||
node = simulation::Traction.find( event->asNodeName );
|
||||
}
|
||||
if( node != nullptr )
|
||||
event->Params[ 9 ].asEditorNode = node;
|
||||
event->Params[ 9 ].asSceneNode = node;
|
||||
else {
|
||||
event->m_ignored = true;
|
||||
ErrorLog( "Bad event: visibility event \"" + event->asName + "\" cannot find item \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Switch: {
|
||||
@@ -1460,7 +1649,6 @@ event_manager::InitEvents() {
|
||||
else {
|
||||
ErrorLog( "Bad event: switch event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Sound: {
|
||||
@@ -1470,7 +1658,6 @@ event_manager::InitEvents() {
|
||||
event->Params[ 9 ].tsTextSound = sound;
|
||||
else
|
||||
ErrorLog( "Bad event: sound event \"" + event->asName + "\" cannot find static sound \"" + event->asNodeName + "\"" );
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_TrackVel: {
|
||||
@@ -1486,7 +1673,6 @@ event_manager::InitEvents() {
|
||||
ErrorLog( "Bad event: track velocity event \"" + event->asName + "\" cannot find track \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_DynVel: {
|
||||
@@ -1500,7 +1686,6 @@ event_manager::InitEvents() {
|
||||
else
|
||||
ErrorLog( "Bad event: vehicle velocity event \"" + event->asName + "\" cannot find vehicle \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
case tp_Multiple: {
|
||||
@@ -1548,7 +1733,6 @@ event_manager::InitEvents() {
|
||||
else
|
||||
ErrorLog( "Bad event: voltage event \"" + event->asName + "\" cannot find power source \"" + event->asNodeName + "\"" );
|
||||
}
|
||||
event->asNodeName = "";
|
||||
break;
|
||||
}
|
||||
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
|
||||
bool
|
||||
event_manager::EventConditon( TEvent *Event ) {
|
||||
|
||||
10
Event.h
10
Event.h
@@ -17,7 +17,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
enum TEventType {
|
||||
tp_Unknown,
|
||||
tp_Sound,
|
||||
tp_SoundPos,
|
||||
tp_Exit,
|
||||
tp_Disable,
|
||||
tp_Velocity,
|
||||
@@ -31,7 +30,6 @@ enum TEventType {
|
||||
tp_TrackVel,
|
||||
tp_Multiple,
|
||||
tp_AddValues,
|
||||
// tp_Ignored, // NOTE: refactored to separate flag
|
||||
tp_CopyValues,
|
||||
tp_WhoIs,
|
||||
tp_LogValues,
|
||||
@@ -61,7 +59,7 @@ union TParam
|
||||
{
|
||||
void *asPointer;
|
||||
TMemCell *asMemCell;
|
||||
editor::basic_node *asEditorNode;
|
||||
scene::basic_node *asSceneNode;
|
||||
glm::dvec3 const *asLocation;
|
||||
TTrack *asTrack;
|
||||
TAnimModel *asModel;
|
||||
@@ -103,6 +101,9 @@ public:
|
||||
TEvent(std::string const &m = "");
|
||||
~TEvent();
|
||||
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 );
|
||||
std::string CommandGet();
|
||||
TCommandType Command();
|
||||
@@ -151,6 +152,9 @@ public:
|
||||
// legacy method, initializes event launchers after deserialization from scenario file
|
||||
void
|
||||
InitLaunchers();
|
||||
// sends basic content of the class in legacy (text) format to provided stream
|
||||
void
|
||||
export_as_text( std::ostream &Output ) const;
|
||||
|
||||
private:
|
||||
// types
|
||||
|
||||
35
MemCell.cpp
35
MemCell.cpp
@@ -164,6 +164,41 @@ void TMemCell::AssignEvents(TEvent *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
|
||||
|
||||
12
MemCell.h
12
MemCell.h
@@ -13,10 +13,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.h"
|
||||
#include "names.h"
|
||||
|
||||
class TMemCell : public editor::basic_node {
|
||||
class TMemCell : public scene::basic_node {
|
||||
|
||||
public:
|
||||
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 );
|
||||
|
||||
@@ -49,6 +50,15 @@ public:
|
||||
void AssignEvents(TEvent *e);
|
||||
|
||||
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
|
||||
std::string szText;
|
||||
double fValue1 { 0.0 };
|
||||
|
||||
3
Names.h
3
Names.h
@@ -60,5 +60,8 @@ public:
|
||||
type_sequence &
|
||||
sequence() {
|
||||
return m_items; }
|
||||
type_sequence const &
|
||||
sequence() const {
|
||||
return m_items; }
|
||||
|
||||
};
|
||||
|
||||
62
Segment.cpp
62
Segment.cpp
@@ -18,8 +18,36 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// 101206 Ra: trapezoidalne drogi
|
||||
// 110806 Ra: odwrócone mapowanie wzdłuż - Point1 == 1.0
|
||||
// helper, restores content of a 3d vector from provided input stream
|
||||
// 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) :
|
||||
pOwner( owner )
|
||||
@@ -62,6 +90,7 @@ bool TSegment::Init( Math3D::vector3 &NewPoint1, Math3D::vector3 NewCPointOut, M
|
||||
// poprawienie przechyłki
|
||||
fRoll1 = glm::radians(fNewRoll1); // Ra: przeliczone jest bardziej przydatne do obliczeń
|
||||
fRoll2 = glm::radians(fNewRoll2);
|
||||
bCurve = bIsCurve;
|
||||
if (Global.bRollFix)
|
||||
{ // Ra: poprawianie przechyłki
|
||||
// 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
|
||||
// Ra: ten kąt jeszcze do przemyślenia jest
|
||||
fDirection = -std::atan2(Point2.x - Point1.x, Point2.z - Point1.z);
|
||||
bCurve = bIsCurve;
|
||||
if (bCurve)
|
||||
{ // przeliczenie współczynników wielomianu, będzie mniej mnożeń i można policzyć pochodne
|
||||
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
|
||||
fLength = ComputeLength();
|
||||
}
|
||||
else
|
||||
fLength = (Point1 - Point2).Length();
|
||||
fStep = fNewStep;
|
||||
else {
|
||||
fLength = ( Point1 - Point2 ).Length();
|
||||
}
|
||||
if (fLength <= 0) {
|
||||
|
||||
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
|
||||
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 = (
|
||||
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
|
||||
|
||||
SafeDeleteArray( fTsBuffer );
|
||||
fTsBuffer = new double[ iSegCount + 1 ];
|
||||
fTsBuffer[ 0 ] = 0.0;
|
||||
for( int i = 1; i < iSegCount; ++i ) {
|
||||
|
||||
18
Segment.h
18
Segment.h
@@ -14,6 +14,24 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "openglgeometrybank.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
|
||||
{ // aproksymacja toru (zwrotnica ma dwa takie, jeden z nich jest aktywny)
|
||||
private:
|
||||
|
||||
523
Track.cpp
523
Track.cpp
@@ -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)
|
||||
{ // pobranie obiektu trajektorii ruchu
|
||||
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");
|
||||
Init(); // ustawia SwitchExtension
|
||||
double segsize = 5.0; // długość odcinka segmentowania
|
||||
switch (eType)
|
||||
{ // Ra: łuki segmentowane co 5m albo 314-kątem foremnym
|
||||
case tt_Table: // obrotnica jest prawie jak zwykły tor
|
||||
|
||||
// path data
|
||||
// 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
|
||||
case tt_Normal:
|
||||
p1 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P1
|
||||
parser->getTokens();
|
||||
*parser >> r1; // pobranie przechyłki w P1
|
||||
cp1 = LoadPoint(parser); // pobranie współrzędnych punktów kontrolnych
|
||||
cp2 = LoadPoint(parser);
|
||||
p2 = LoadPoint(parser) + pOrigin; // pobranie współrzędnych P2
|
||||
parser->getTokens(2);
|
||||
*parser >> r2 >> fRadius; // pobranie przechyłki w P1 i promienia
|
||||
fRadius = fabs(fRadius); // we wpisie może być ujemny
|
||||
}
|
||||
case tt_Normal: {
|
||||
// pobranie współrzędnych P1
|
||||
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 ];
|
||||
fRadius = std::abs( path.radius ); // we wpisie może być ujemny
|
||||
|
||||
if (iCategoryFlag & 1)
|
||||
{ // zero na główce szyny
|
||||
p1.y += 0.18;
|
||||
@@ -502,7 +518,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
|
||||
if( fRadius != 0 ) {
|
||||
// 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 {
|
||||
// HACK: crude check whether claimed straight is an actual straight piece
|
||||
@@ -512,7 +532,11 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
}
|
||||
else {
|
||||
// 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))
|
||||
iTrapezoid = 1; // są przechyłki do uwzględniania w rysowaniu
|
||||
|
||||
if (eType == tt_Table) // obrotnica ma doklejkę
|
||||
{ // SwitchExtension=new TSwitchExtension(this,1); //dodatkowe zmienne dla obrotnicy
|
||||
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
|
||||
}
|
||||
break;
|
||||
|
||||
case tt_Cross: // skrzyżowanie dróg - 4 punkty z wektorami kontrolnymi
|
||||
segsize = 1.0; // specjalne segmentowanie ze względu na małe promienie
|
||||
}
|
||||
case tt_Cross: {
|
||||
// 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_Switch: // zwrotnica
|
||||
case tt_Switch: { // zwrotnica
|
||||
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ę
|
||||
// wtedy dzieli się na dodatkowe odcinki (po 0.2m, bo R=0) i animację diabli biorą
|
||||
// Ra: na razie nie podejmuję się przerabiania iglic
|
||||
|
||||
// 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)
|
||||
{ // zero na główce szyny
|
||||
p1.y += 0.18;
|
||||
p2.y += 0.18;
|
||||
// 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)))
|
||||
SwitchExtension->Segments[0]->Init(p1, p1 + cp1, p2 + cp2, p2, segsize, r1, r2);
|
||||
else
|
||||
SwitchExtension->Segments[0]->Init(p1, p2, segsize, r1, r2);
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( ( ( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ).Length() < 0.02 )
|
||||
|| ( ( ( 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)
|
||||
{ // zero na główce szyny
|
||||
p3.y += 0.18;
|
||||
@@ -606,25 +667,54 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||
}
|
||||
|
||||
if (fRadiusTable[1] > 0)
|
||||
segsize = clamp( 0.2 + fRadiusTable[ 1 ] * 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
|
||||
cp3 = (p3 + p3 + p4) / 3.0 - p3; // jak jest prosty, to się zoptymalizuje
|
||||
cp4 = (p3 + p4 + p4) / 3.0 - p4;
|
||||
segsize = 5.0;
|
||||
} // ułomny prosty
|
||||
|
||||
if (!(cp3 == Math3D::vector3(0, 0, 0)) && !(cp4 == Math3D::vector3(0, 0, 0)))
|
||||
{ // dla skrzyżowania dróg dać odwrotnie końce, żeby brzegi generować lewym
|
||||
if (eType != tt_Cross)
|
||||
SwitchExtension->Segments[1]->Init(p3, p3 + cp3, p4 + cp4, p4, segsize, r3, r4);
|
||||
else
|
||||
SwitchExtension->Segments[1]->Init(p4, p4 + cp4, p3 + cp3, p3, segsize, r4, r3); // odwrócony
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( ( ( ( p3 + p3 + p4 ) / 3.0 - p3 - cp3 ).Length() < 0.02 )
|
||||
|| ( ( ( p3 + p4 + p4 ) / 3.0 - p4 + cp3 ).Length() < 0.02 ) ) {
|
||||
// "prostowanie" prostych z kontrolnymi, dokładność 2cm
|
||||
cp3 = cp4 = Math3D::vector3( 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if( fRadiusTable[ 1 ] != 0 ) {
|
||||
// gdy podany promień
|
||||
segsize =
|
||||
clamp(
|
||||
std::abs( fRadiusTable[ 1 ] ) * ( 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( ( 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)
|
||||
{ // 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;
|
||||
double a1, a2;
|
||||
v1 = SwitchExtension->Segments[0]->FastGetPoint_1() -
|
||||
SwitchExtension->Segments[0]->FastGetPoint_0();
|
||||
v2 = SwitchExtension->Segments[1]->FastGetPoint_1() -
|
||||
SwitchExtension->Segments[1]->FastGetPoint_0();
|
||||
v1 = SwitchExtension->Segments[0]->FastGetPoint_1()
|
||||
- SwitchExtension->Segments[0]->FastGetPoint_0();
|
||||
v2 = SwitchExtension->Segments[1]->FastGetPoint_1()
|
||||
- SwitchExtension->Segments[1]->FastGetPoint_0();
|
||||
a1 = atan2(v1.x, v1.z);
|
||||
a2 = atan2(v2.x, v2.z);
|
||||
a2 = a2 - a1;
|
||||
@@ -660,7 +750,10 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
SwitchExtension->RightSwitch = a2 < 0; // lustrzany układ OXY...
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// optional attributes
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
@@ -707,9 +800,9 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
|
||||
parser->getTokens();
|
||||
*parser >> fVelocity; //*0.28; McZapkie-010602
|
||||
if (SwitchExtension) // jeśli tor ruchomy
|
||||
if (std::fabs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
|
||||
SwitchExtension->fVelocity = static_cast<float>(fVelocity); // zapamiętanie głównego ograniczenia; a
|
||||
// np. -40 ogranicza tylko na bok
|
||||
if (std::abs(fVelocity) >= 1.0) //żeby zero nie ograniczało dożywotnio
|
||||
// zapamiętanie głównego ograniczenia; a np. -40 ogranicza tylko na bok
|
||||
SwitchExtension->fVelocity = static_cast<float>(fVelocity);
|
||||
}
|
||||
else if (str == "isolated")
|
||||
{ // 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
|
||||
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
|
||||
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit )
|
||||
{
|
||||
bool bError = false;
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEvent0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEvent0 == nullptr ) {
|
||||
evEvent0 = NewEvent0;
|
||||
/*
|
||||
// preserve event names, we'll need them if we want the scenario export to be unaffected by missing events and such
|
||||
asEvent0Name = "";
|
||||
*/
|
||||
iEvents |= 1; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -801,14 +899,18 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEvent1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEvent1 == nullptr ) {
|
||||
evEvent1 = NewEvent1;
|
||||
/*
|
||||
asEvent1Name = "";
|
||||
*/
|
||||
iEvents |= 2; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -819,14 +921,18 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEvent2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEvent2 == nullptr ) {
|
||||
evEvent2 = NewEvent2;
|
||||
/*
|
||||
asEvent2Name = "";
|
||||
*/
|
||||
iEvents |= 4; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -838,20 +944,25 @@ bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent
|
||||
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;
|
||||
|
||||
if( NewEvent0 == nullptr ) {
|
||||
if( false == asEventall0Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall0 == nullptr ) {
|
||||
evEventall0 = NewEvent0;
|
||||
/*
|
||||
// preserve event names, we'll need them if we want the scenario export to be unaffected by missing events and such
|
||||
asEventall0Name = "";
|
||||
*/
|
||||
iEvents |= 8; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -862,14 +973,18 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
|
||||
|
||||
if( NewEvent1 == nullptr ) {
|
||||
if( false == asEventall1Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall1 == nullptr ) {
|
||||
evEventall1 = NewEvent1;
|
||||
/*
|
||||
asEventall1Name = "";
|
||||
*/
|
||||
iEvents |= 16; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -880,14 +995,18 @@ bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEv
|
||||
|
||||
if( NewEvent2 == nullptr ) {
|
||||
if( false == asEventall2Name.empty() ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
bError = true;
|
||||
if( true == Explicit ) {
|
||||
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( evEventall2 == nullptr ) {
|
||||
evEventall2 = NewEvent2;
|
||||
/*
|
||||
asEventall2Name = "";
|
||||
*/
|
||||
iEvents |= 32; // sumaryczna informacja o eventach
|
||||
}
|
||||
else {
|
||||
@@ -1404,6 +1523,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
{szyna[ i ].texture.x, 0.f} };
|
||||
}
|
||||
// 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)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
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 );
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
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 ) );
|
||||
vertices.clear();
|
||||
// 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 ) );
|
||||
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 );
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
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 ) );
|
||||
vertices.clear();
|
||||
// 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 ) );
|
||||
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
|
||||
Geometry1.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
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 ) );
|
||||
vertices.clear();
|
||||
// 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 ) );
|
||||
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
|
||||
Geometry2.emplace_back( GfxRenderer.Insert( vertices, Bank, GL_TRIANGLE_STRIP ) );
|
||||
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 ) );
|
||||
vertices.clear();
|
||||
// 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 ) );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2220,9 +2340,13 @@ bool TTrack::Switch(int i, float const t, float const d)
|
||||
iNextDirection = SwitchExtension->iNextDirection[i];
|
||||
iPrevDirection = SwitchExtension->iPrevDirection[i];
|
||||
fRadius = fRadiusTable[i]; // McZapkie: wybor promienia toru
|
||||
if (SwitchExtension->fVelocity <=
|
||||
-2) //-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
|
||||
if( SwitchExtension->fVelocity <= -2 ) {
|
||||
//-1 oznacza maksymalną prędkość, a dalsze ujemne to ograniczenie na bok
|
||||
fVelocity = i ? -SwitchExtension->fVelocity : -1;
|
||||
}
|
||||
else {
|
||||
fVelocity = SwitchExtension->fVelocity;
|
||||
}
|
||||
if (SwitchExtension->pOwner ? SwitchExtension->pOwner->RaTrackAnimAdd(this) :
|
||||
true) // jeśli nie dodane do animacji
|
||||
{ // nie ma się co bawić
|
||||
@@ -2455,17 +2579,18 @@ TTrack * TTrack::RaAnimate()
|
||||
|
||||
gfx::vertex_array vertices;
|
||||
|
||||
auto const bladelength { 2 * Global.SplineFidelity };
|
||||
if (SwitchExtension->RightSwitch)
|
||||
{ // nowa wersja z SPKS, ale odwrotnie lewa/prawa
|
||||
if( m_material1 ) {
|
||||
// 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 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// 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 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2473,13 +2598,13 @@ TTrack * TTrack::RaAnimate()
|
||||
else { // lewa działa lepiej niż prawa
|
||||
if( m_material1 ) {
|
||||
// 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 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
if( m_material2 ) {
|
||||
// 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 ] );
|
||||
vertices.clear();
|
||||
}
|
||||
@@ -2659,32 +2784,188 @@ TTrack::endpoints() const {
|
||||
}
|
||||
}
|
||||
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
float
|
||||
TTrack::radius_() {
|
||||
|
||||
auto const points = endpoints();
|
||||
auto const points { endpoints() };
|
||||
auto radius { 0.f };
|
||||
for( auto &point : points ) {
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
radius = std::max(
|
||||
radius,
|
||||
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)
|
||||
{ // poprawienie przechyłki wymaga wydłużenia podsypki
|
||||
fTexHeight1 += dh;
|
||||
fTexHeightOffset += dh;
|
||||
};
|
||||
|
||||
void TTrack::VelocitySet(float v)
|
||||
{ // ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
||||
if (SwitchExtension ? SwitchExtension->fVelocity >= 0.0 : false)
|
||||
{ // zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
|
||||
if (v > SwitchExtension->fVelocity ? true : v < 0.0)
|
||||
return void(fVelocity =
|
||||
SwitchExtension->fVelocity); // maksymalnie tyle, ile było we wpisie
|
||||
// ustawienie prędkości z ograniczeniem do pierwotnej wartości (zapisanej w scenerii)
|
||||
void TTrack::VelocitySet(float v) {
|
||||
// TBD, TODO: add a variable to preserve potential speed limit set by the track configuration on basic track pieces
|
||||
if( ( SwitchExtension )
|
||||
&& ( SwitchExtension->fVelocity != -1 ) ) {
|
||||
// zwrotnica może mieć odgórne ograniczenie, nieprzeskakiwalne eventem
|
||||
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()
|
||||
@@ -2800,11 +3081,13 @@ path_table::InitTracks() {
|
||||
track->AssignEvents(
|
||||
simulation::Events.FindEvent( trackname + ":event0" ),
|
||||
simulation::Events.FindEvent( trackname + ":event1" ),
|
||||
simulation::Events.FindEvent( trackname + ":event2" ) );
|
||||
simulation::Events.FindEvent( trackname + ":event2" ),
|
||||
false );
|
||||
track->AssignallEvents(
|
||||
simulation::Events.FindEvent( trackname + ":eventall0" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall1" ),
|
||||
simulation::Events.FindEvent( trackname + ":eventall2" ) );
|
||||
simulation::Events.FindEvent( trackname + ":eventall2" ),
|
||||
false );
|
||||
}
|
||||
|
||||
switch (track->eType) {
|
||||
@@ -2948,6 +3231,8 @@ path_table::InitTracks() {
|
||||
scene::node_data nodedata;
|
||||
nodedata.name = isolated->asName;
|
||||
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 );
|
||||
isolated->pMemCell = memorycell; // wskaźnik komóki przekazany do odcinka izolowanego
|
||||
}
|
||||
|
||||
23
Track.h
23
Track.h
@@ -124,7 +124,7 @@ private:
|
||||
};
|
||||
|
||||
// trajektoria ruchu - opakowanie
|
||||
class TTrack : public editor::basic_node {
|
||||
class TTrack : public scene::basic_node {
|
||||
|
||||
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 fTexRatio2 = 1.0f; // proporcja boków tekstury chodnika (żeby zaoszczędzić na rozmiarach tekstur...)
|
||||
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 fTexSlope = 0.9f;
|
||||
|
||||
@@ -152,6 +153,8 @@ private:
|
||||
geometryhandle_sequence Geometry1; // geometry chunks textured with texture 1
|
||||
geometryhandle_sequence Geometry2; // geometry chunks textured with texture 2
|
||||
|
||||
std::vector<segment_data> m_paths; // source data for owned paths
|
||||
|
||||
public:
|
||||
typedef std::deque<TDynamicObject *> dynamics_sequence;
|
||||
dynamics_sequence Dynamics;
|
||||
@@ -231,8 +234,8 @@ public:
|
||||
SwitchExtension->iRoads - 1 :
|
||||
1 ); }
|
||||
void Load(cParser *parser, Math3D::vector3 pOrigin);
|
||||
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2);
|
||||
bool AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit = true );
|
||||
bool AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2, bool const Explicit = true );
|
||||
bool AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus);
|
||||
bool CheckDynamicObject(TDynamicObject *Dynamic);
|
||||
bool AddDynamicObject(TDynamicObject *Dynamic);
|
||||
@@ -270,10 +273,16 @@ public:
|
||||
double VelocityGet();
|
||||
void ConnectionsLog();
|
||||
|
||||
protected:
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
radius_();
|
||||
private:
|
||||
// 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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
84
Traction.cpp
84
Traction.cpp
@@ -529,18 +529,6 @@ double TTraction::VoltageGet(double u, double i)
|
||||
return 0.0; // gdy nie podłączony wcale?
|
||||
};
|
||||
|
||||
// calculates path's bounding radius
|
||||
void
|
||||
TTraction::radius_() {
|
||||
|
||||
auto const points = endpoints();
|
||||
for( auto &point : points ) {
|
||||
m_area.radius = std::max(
|
||||
m_area.radius,
|
||||
static_cast<float>( glm::length( m_area.center - point ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3
|
||||
TTraction::wire_color() const {
|
||||
|
||||
@@ -580,6 +568,7 @@ TTraction::wire_color() const {
|
||||
color.r *= Global.DayLight.ambient[ 0 ];
|
||||
color.g *= Global.DayLight.ambient[ 1 ];
|
||||
color.b *= Global.DayLight.ambient[ 2 ];
|
||||
color *= 0.5f;
|
||||
}
|
||||
else {
|
||||
// tymczasowo pokazanie zasilanych odcinków
|
||||
@@ -675,6 +664,77 @@ TTraction::wire_color() const {
|
||||
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
|
||||
|
||||
17
Traction.h
17
Traction.h
@@ -18,7 +18,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
class TTractionPowerSource;
|
||||
|
||||
class TTraction : public editor::basic_node {
|
||||
class TTraction : public scene::basic_node {
|
||||
|
||||
friend class opengl_renderer;
|
||||
|
||||
@@ -73,13 +73,18 @@ class TTraction : public editor::basic_node {
|
||||
void PowerSet(TTractionPowerSource *ps);
|
||||
double VoltageGet(double u, double i);
|
||||
|
||||
protected:
|
||||
// calculates piece's bounding radius
|
||||
void
|
||||
radius_();
|
||||
|
||||
private:
|
||||
// methods
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -141,6 +141,52 @@ void TTractionPowerSource::PowerSet(TTractionPowerSource *ps)
|
||||
// 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
|
||||
|
||||
@@ -13,9 +13,33 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "scenenode.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 VoltageFrequency = 0.0;
|
||||
double InternalRes = 0.2;
|
||||
@@ -34,20 +58,6 @@ class TTractionPowerSource : public editor::basic_node {
|
||||
double FuseTimer = 0.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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
84
World.cpp
84
World.cpp
@@ -311,49 +311,47 @@ bool TWorld::Init( GLFWwindow *Window ) {
|
||||
|
||||
void TWorld::OnKeyDown(int cKey) {
|
||||
// dump keypress info in the log
|
||||
if( !Global.iPause ) {
|
||||
// podczas pauzy klawisze nie działają
|
||||
std::string keyinfo;
|
||||
auto keyname = glfwGetKeyName( cKey, 0 );
|
||||
if( keyname != nullptr ) {
|
||||
keyinfo += std::string( keyname );
|
||||
}
|
||||
else {
|
||||
switch( cKey ) {
|
||||
// podczas pauzy klawisze nie działają
|
||||
std::string keyinfo;
|
||||
auto keyname = glfwGetKeyName( cKey, 0 );
|
||||
if( keyname != nullptr ) {
|
||||
keyinfo += std::string( keyname );
|
||||
}
|
||||
else {
|
||||
switch( cKey ) {
|
||||
|
||||
case GLFW_KEY_SPACE: { keyinfo += "Space"; break; }
|
||||
case GLFW_KEY_ENTER: { keyinfo += "Enter"; break; }
|
||||
case GLFW_KEY_ESCAPE: { keyinfo += "Esc"; break; }
|
||||
case GLFW_KEY_TAB: { keyinfo += "Tab"; break; }
|
||||
case GLFW_KEY_INSERT: { keyinfo += "Insert"; break; }
|
||||
case GLFW_KEY_DELETE: { keyinfo += "Delete"; break; }
|
||||
case GLFW_KEY_HOME: { keyinfo += "Home"; break; }
|
||||
case GLFW_KEY_END: { keyinfo += "End"; break; }
|
||||
case GLFW_KEY_F1: { keyinfo += "F1"; break; }
|
||||
case GLFW_KEY_F2: { keyinfo += "F2"; break; }
|
||||
case GLFW_KEY_F3: { keyinfo += "F3"; break; }
|
||||
case GLFW_KEY_F4: { keyinfo += "F4"; break; }
|
||||
case GLFW_KEY_F5: { keyinfo += "F5"; break; }
|
||||
case GLFW_KEY_F6: { keyinfo += "F6"; break; }
|
||||
case GLFW_KEY_F7: { keyinfo += "F7"; break; }
|
||||
case GLFW_KEY_F8: { keyinfo += "F8"; break; }
|
||||
case GLFW_KEY_F9: { keyinfo += "F9"; break; }
|
||||
case GLFW_KEY_F10: { keyinfo += "F10"; break; }
|
||||
case GLFW_KEY_F11: { keyinfo += "F11"; break; }
|
||||
case GLFW_KEY_F12: { keyinfo += "F12"; break; }
|
||||
case GLFW_KEY_PAUSE: { keyinfo += "Pause"; break; }
|
||||
}
|
||||
case GLFW_KEY_SPACE: { keyinfo += "Space"; break; }
|
||||
case GLFW_KEY_ENTER: { keyinfo += "Enter"; break; }
|
||||
case GLFW_KEY_ESCAPE: { keyinfo += "Esc"; break; }
|
||||
case GLFW_KEY_TAB: { keyinfo += "Tab"; break; }
|
||||
case GLFW_KEY_INSERT: { keyinfo += "Insert"; break; }
|
||||
case GLFW_KEY_DELETE: { keyinfo += "Delete"; break; }
|
||||
case GLFW_KEY_HOME: { keyinfo += "Home"; break; }
|
||||
case GLFW_KEY_END: { keyinfo += "End"; break; }
|
||||
case GLFW_KEY_F1: { keyinfo += "F1"; break; }
|
||||
case GLFW_KEY_F2: { keyinfo += "F2"; break; }
|
||||
case GLFW_KEY_F3: { keyinfo += "F3"; break; }
|
||||
case GLFW_KEY_F4: { keyinfo += "F4"; break; }
|
||||
case GLFW_KEY_F5: { keyinfo += "F5"; break; }
|
||||
case GLFW_KEY_F6: { keyinfo += "F6"; break; }
|
||||
case GLFW_KEY_F7: { keyinfo += "F7"; break; }
|
||||
case GLFW_KEY_F8: { keyinfo += "F8"; break; }
|
||||
case GLFW_KEY_F9: { keyinfo += "F9"; break; }
|
||||
case GLFW_KEY_F10: { keyinfo += "F10"; break; }
|
||||
case GLFW_KEY_F11: { keyinfo += "F11"; break; }
|
||||
case GLFW_KEY_F12: { keyinfo += "F12"; break; }
|
||||
case GLFW_KEY_PAUSE: { keyinfo += "Pause"; break; }
|
||||
}
|
||||
if( keyinfo.empty() == false ) {
|
||||
}
|
||||
if( keyinfo.empty() == false ) {
|
||||
|
||||
std::string keymodifiers;
|
||||
if( Global.shiftState )
|
||||
keymodifiers += "[Shift]+";
|
||||
if( Global.ctrlState )
|
||||
keymodifiers += "[Ctrl]+";
|
||||
std::string keymodifiers;
|
||||
if( Global.shiftState )
|
||||
keymodifiers += "[Shift]+";
|
||||
if( Global.ctrlState )
|
||||
keymodifiers += "[Ctrl]+";
|
||||
|
||||
WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" );
|
||||
}
|
||||
WriteLog( "Key pressed: " + keymodifiers + "[" + keyinfo + "]" );
|
||||
}
|
||||
|
||||
// actual key processing
|
||||
@@ -504,6 +502,14 @@ void TWorld::OnKeyDown(int cKey) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLFW_KEY_F11: {
|
||||
// scenery export
|
||||
if( Global.ctrlState
|
||||
&& Global.shiftState ) {
|
||||
simulation::State.export_as_text( Global.SceneryFile );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GLFW_KEY_F12: {
|
||||
// quick debug mode toggle
|
||||
if( Global.ctrlState
|
||||
|
||||
35
scene.cpp
35
scene.cpp
@@ -228,6 +228,17 @@ basic_cell::deserialize( std::istream &Input ) {
|
||||
|| ( 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
|
||||
void
|
||||
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
|
||||
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,
|
||||
@@ -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
|
||||
void
|
||||
basic_section::insert( shape_node Shape ) {
|
||||
@@ -949,6 +970,18 @@ basic_region::deserialize( std::string const &Scenariofile ) {
|
||||
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
|
||||
void
|
||||
basic_region::TrackJoin( TTrack *Track ) {
|
||||
|
||||
11
scene.h
11
scene.h
@@ -88,6 +88,9 @@ public:
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
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
|
||||
void
|
||||
insert( shape_node Shape );
|
||||
@@ -149,7 +152,7 @@ private:
|
||||
using eventlauncher_sequence = std::vector<TEventLauncher *>;
|
||||
// methods
|
||||
void
|
||||
enclose_area( editor::basic_node *Node );
|
||||
enclose_area( scene::basic_node *Node );
|
||||
// members
|
||||
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) };
|
||||
bool m_active { false }; // whether the cell holds any actual data
|
||||
@@ -199,6 +202,9 @@ public:
|
||||
// restores content of the class from provided stream
|
||||
void
|
||||
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
|
||||
void
|
||||
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
|
||||
bool
|
||||
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
|
||||
void
|
||||
TrackJoin( TTrack *Track );
|
||||
|
||||
@@ -142,7 +142,7 @@ shape_node::deserialize( std::istream &Input ) {
|
||||
|
||||
// restores content of the node from provided input stream
|
||||
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
|
||||
m_name = Nodedata.name;
|
||||
@@ -523,7 +523,7 @@ lines_node::deserialize( std::istream &Input ) {
|
||||
|
||||
// restores content of the node from provded input stream
|
||||
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
|
||||
m_name = Nodedata.name;
|
||||
@@ -684,12 +684,9 @@ memory_node::deserialize( cParser &Input, node_data const &Nodedata ) {
|
||||
memorycell.Load( &Input );
|
||||
}
|
||||
*/
|
||||
} // scene
|
||||
|
||||
|
||||
|
||||
namespace editor {
|
||||
|
||||
basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||
m_name( Nodedata.name )
|
||||
{
|
||||
@@ -700,23 +697,69 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||
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 &
|
||||
basic_node::radius() {
|
||||
|
||||
if( m_area.radius == -1.0 ) {
|
||||
// calculate if needed
|
||||
radius_();
|
||||
m_area.radius = radius_();
|
||||
}
|
||||
return m_area.radius;
|
||||
}
|
||||
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
// by default nodes are 'virtual don't extend from their center point
|
||||
void
|
||||
float
|
||||
basic_node::radius_() {
|
||||
|
||||
m_area.radius = 0.f;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
} // editor
|
||||
} // scene
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
34
scenenode.h
34
scenenode.h
@@ -112,7 +112,7 @@ public:
|
||||
deserialize( std::istream &Input );
|
||||
// restores content of the node from provided input stream
|
||||
shape_node &
|
||||
deserialize( cParser &Input, scene::node_data const &Nodedata );
|
||||
import( cParser &Input, scene::node_data const &Nodedata );
|
||||
// imports data from provided submodel
|
||||
shape_node &
|
||||
convert( TSubModel const *Submodel );
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
deserialize( std::istream &Input );
|
||||
// restores content of the node from provided input stream
|
||||
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
|
||||
bool
|
||||
merge( lines_node &Lines );
|
||||
@@ -295,12 +295,9 @@ private:
|
||||
TTrack * m_path;
|
||||
};
|
||||
*/
|
||||
} // scene
|
||||
|
||||
|
||||
|
||||
namespace editor {
|
||||
|
||||
// base interface for nodes which can be actvated in scenario editor
|
||||
struct basic_node {
|
||||
|
||||
@@ -310,6 +307,15 @@ public:
|
||||
// destructor
|
||||
virtual ~basic_node() = default;
|
||||
// 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 &
|
||||
name() const;
|
||||
void
|
||||
@@ -324,15 +330,23 @@ public:
|
||||
visible() const;
|
||||
|
||||
protected:
|
||||
// methods
|
||||
// radius() subclass details, calculates node's bounding radius
|
||||
virtual void radius_();
|
||||
// members
|
||||
scene::bounding_area m_area;
|
||||
bool m_visible { true };
|
||||
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||
bool m_visible { true }; // visibility flag
|
||||
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
|
||||
@@ -365,6 +379,6 @@ basic_node::visible() const {
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
} // editor
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "uilayer.h"
|
||||
#include "renderer.h"
|
||||
|
||||
|
||||
namespace simulation {
|
||||
|
||||
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
|
||||
Region->serialize( Scenariofile );
|
||||
}
|
||||
|
||||
Global.iPause &= ~0x10; // koniec pauzy wczytywania
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -409,7 +408,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_shape(
|
||||
scene::shape_node().deserialize(
|
||||
scene::shape_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad,
|
||||
true );
|
||||
@@ -426,7 +425,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
if( false == Scratchpad.binary.terrain ) {
|
||||
|
||||
simulation::Region->insert_lines(
|
||||
scene::lines_node().deserialize(
|
||||
scene::lines_node().import(
|
||||
Input, nodedata ),
|
||||
Scratchpad );
|
||||
}
|
||||
@@ -439,7 +438,7 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|
||||
|
||||
auto *memorycell { deserialize_memorycell( Input, Scratchpad, nodedata ) };
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory cell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
/*
|
||||
// TODO: implement this
|
||||
@@ -897,6 +896,65 @@ state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratc
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -36,6 +36,9 @@ public:
|
||||
update( double Deltatime, int Iterationcount );
|
||||
bool
|
||||
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:
|
||||
// methods
|
||||
@@ -69,6 +72,7 @@ private:
|
||||
void skip_until( cParser &Input, std::string const &Token );
|
||||
// transforms provided location by specifed rotation and offset
|
||||
glm::dvec3 transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad );
|
||||
|
||||
};
|
||||
|
||||
extern state_manager State;
|
||||
|
||||
37
sound.cpp
37
sound.cpp
@@ -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
|
||||
sound_source &
|
||||
sound_source::copy_sounds( sound_source const &Source ) {
|
||||
|
||||
3
sound.h
3
sound.h
@@ -60,6 +60,9 @@ public:
|
||||
deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 );
|
||||
sound_source &
|
||||
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
|
||||
sound_source &
|
||||
copy_sounds( sound_source const &Source );
|
||||
|
||||
@@ -98,6 +98,7 @@ ui_layer::on_key( int const Key, int const Action ) {
|
||||
case GLFW_KEY_F8:
|
||||
case GLFW_KEY_F9:
|
||||
case GLFW_KEY_F10:
|
||||
case GLFW_KEY_F11:
|
||||
case GLFW_KEY_F12: { // ui mode selectors
|
||||
|
||||
if( ( true == Global.ctrlState )
|
||||
|
||||
Reference in New Issue
Block a user