Merge branch 'tmj-dev' into milek-dev

This commit is contained in:
milek7
2018-06-15 18:58:03 +02:00
54 changed files with 2310 additions and 927 deletions

651
Track.cpp
View File

@@ -345,14 +345,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ń
@@ -475,20 +467,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;
@@ -504,7 +520,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
@@ -514,7 +534,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 );
}
}
@@ -531,6 +555,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
@@ -551,56 +576,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;
@@ -608,25 +669,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
@@ -648,10 +738,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;
@@ -662,7 +752,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;
@@ -672,46 +765,46 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
{
parser->getTokens();
*parser >> token;
asEvent0Name = token;
m_events0.emplace_back( token, nullptr );
}
else if (str == "event1")
{
parser->getTokens();
*parser >> token;
asEvent1Name = token;
m_events1.emplace_back( token, nullptr );
}
else if (str == "event2")
{
parser->getTokens();
*parser >> token;
asEvent2Name = token;
m_events2.emplace_back( token, nullptr );
}
else if (str == "eventall0")
{
parser->getTokens();
*parser >> token;
asEventall0Name = token;
m_events0all.emplace_back( token, nullptr );
}
else if (str == "eventall1")
{
parser->getTokens();
*parser >> token;
asEventall1Name = token;
m_events1all.emplace_back( token, nullptr );
}
else if (str == "eventall2")
{
parser->getTokens();
*parser >> token;
asEventall2Name = token;
m_events2all.emplace_back( token, nullptr );
}
else if (str == "velocity")
{
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
@@ -778,127 +871,44 @@ void TTrack::Load(cParser *parser, Math3D::vector3 pOrigin)
/ 3.0 } );
}
// TODO: refactor this mess
bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
{
bool bError = false;
bool TTrack::AssignEvents() {
if( NewEvent0 == nullptr ) {
if( false == asEvent0Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true;
}
}
else {
if( evEvent0 == nullptr ) {
evEvent0 = NewEvent0;
asEvent0Name = "";
iEvents |= 1; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
bool lookupfail { false };
std::vector< std::pair< std::string, event_sequence * > > const eventsequences {
{ "event0", &m_events0 }, { "eventall0", &m_events0all },
{ "event1", &m_events1 }, { "eventall1", &m_events1all },
{ "event2", &m_events2 }, { "eventall2", &m_events2all } };
for( auto &eventsequence : eventsequences ) {
for( auto &event : *( eventsequence.second ) ) {
event.second = simulation::Events.FindEvent( event.first );
if( event.second != nullptr ) {
m_events = true;
}
else {
ErrorLog( "Bad event: event \"" + event.first + "\" assigned to track \"" + m_name + "\" does not exist" );
lookupfail = true;
}
}
}
if( NewEvent1 == nullptr ) {
if( false == asEvent1Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true;
}
}
else {
if( evEvent1 == nullptr ) {
evEvent1 = NewEvent1;
asEvent1Name = "";
iEvents |= 2; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
auto const trackname { name() };
if( ( Global.iHiddenEvents & 1 )
&& ( false == trackname.empty() ) ) {
// jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę
for( auto &eventsequence : eventsequences ) {
auto *event = simulation::Events.FindEvent( trackname + ':' + eventsequence.first );
if( event != nullptr ) {
// HACK: auto-associated events come with empty lookup string, to avoid including them in the text format export
eventsequence.second->emplace_back( "", event );
m_events = true;
}
}
}
if( NewEvent2 == nullptr ) {
if( false == asEvent2Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true;
}
}
else {
if( evEvent2 == nullptr ) {
evEvent2 = NewEvent2;
asEvent2Name = "";
iEvents |= 4; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
}
}
return ( bError == false );
}
bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2)
{
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;
}
}
else {
if( evEventall0 == nullptr ) {
evEventall0 = NewEvent0;
asEventall0Name = "";
iEvents |= 8; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
}
}
if( NewEvent1 == nullptr ) {
if( false == asEventall1Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true;
}
}
else {
if( evEventall1 == nullptr ) {
evEventall1 = NewEvent1;
asEventall1Name = "";
iEvents |= 16; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
}
}
if( NewEvent2 == nullptr ) {
if( false == asEventall2Name.empty() ) {
ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + m_name + "\" does not exist" );
bError = true;
}
}
else {
if( evEventall2 == nullptr ) {
evEventall2 = NewEvent2;
asEventall2Name = "";
iEvents |= 32; // sumaryczna informacja o eventach
}
else {
ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" );
bError = true;
}
}
return ( bError == false );
return ( lookupfail == false );
}
bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus)
@@ -1406,6 +1416,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;
@@ -1414,11 +1425,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();
}
@@ -1427,11 +1438,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();
}
@@ -1444,11 +1455,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();
}
@@ -1457,11 +1468,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();
}
@@ -2222,9 +2233,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ć
@@ -2457,17 +2472,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();
}
@@ -2475,13 +2491,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();
}
@@ -2661,32 +2677,184 @@ 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
std::vector< std::pair< std::string, event_sequence const * > > const eventsequences {
{ "event0", &m_events0 }, { "eventall0", &m_events0all },
{ "event1", &m_events1 }, { "eventall1", &m_events1all },
{ "event2", &m_events2 }, { "eventall2", &m_events2all } };
for( auto &eventsequence : eventsequences ) {
for( auto &event : *( eventsequence.second ) ) {
if( false == event.first.empty() ) {
Output
<< eventsequence.first << ' '
<< event.first << ' ';
}
}
}
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()
@@ -2784,31 +2952,10 @@ path_table::InitTracks() {
for( auto first = std::rbegin(m_items); first != std::rend(m_items); ++first ) {
auto *track = *first;
#endif
track->AssignEvents(
simulation::Events.FindEvent( track->asEvent0Name ),
simulation::Events.FindEvent( track->asEvent1Name ),
simulation::Events.FindEvent( track->asEvent2Name ) );
track->AssignallEvents(
simulation::Events.FindEvent( track->asEventall0Name ),
simulation::Events.FindEvent( track->asEventall1Name ),
simulation::Events.FindEvent( track->asEventall2Name ) );
track->AssignEvents();
auto const trackname { track->name() };
if( ( Global.iHiddenEvents & 1 )
&& ( false == trackname.empty() ) ) {
// jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę
track->AssignEvents(
simulation::Events.FindEvent( trackname + ":event0" ),
simulation::Events.FindEvent( trackname + ":event1" ),
simulation::Events.FindEvent( trackname + ":event2" ) );
track->AssignallEvents(
simulation::Events.FindEvent( trackname + ":eventall0" ),
simulation::Events.FindEvent( trackname + ":eventall1" ),
simulation::Events.FindEvent( trackname + ":eventall2" ) );
}
switch (track->eType) {
// TODO: re-enable
case tt_Table: {
@@ -2950,6 +3097,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
}