basic scenery data export in legacy text format

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

View File

@@ -423,13 +423,6 @@ TAnimModel::~TAnimModel()
SafeDelete(pRoot);
}
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";
}
//---------------------------------------------------------------------------

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

@@ -18,8 +18,36 @@ http://mozilla.org/MPL/2.0/.
//---------------------------------------------------------------------------
// 101206 Ra: trapezoidalne drogi
// 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 ) {

View File

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

@@ -343,14 +343,6 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
}
}
Math3D::vector3 LoadPoint(cParser *parser)
{ // pobranie współrzędnych punktu
Math3D::vector3 p;
parser->getTokens(3);
*parser >> p.x >> p.y >> p.z;
return p;
}
void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
{ // 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
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -60,6 +60,9 @@ public:
deserialize( cParser &Input, sound_type const Legacytype, int const Legacyparameters = 0, int const Chunkrange = 100 );
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 );

View File

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