mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-03 16:40:21 +01:00
Merge remote-tracking branch 'origin/feat/switch-blades' into feat/renderers-cleanup
This commit is contained in:
@@ -96,6 +96,28 @@ bool cut_rails( TTrack const &Track ) {
|
||||
Track.eType == tt_Switch && Track.SwitchExtension && Track.SwitchExtension->m_frogs && Track.SwitchExtension->Segments[ 0 ] && Track.SwitchExtension->Segments[ 1 ] );
|
||||
}
|
||||
|
||||
// a track with rails laid, cut or whole
|
||||
bool railed( TTrack const &Track ) {
|
||||
|
||||
return ( Track.iCategoryFlag & 15 ) == 1
|
||||
&& Track.m_material1 != null_handle
|
||||
&& false == Track.m_editorremoved
|
||||
&& ( Track.eType == tt_Normal ? Track.Segment != nullptr :
|
||||
Track.eType == tt_Switch && Track.SwitchExtension && Track.SwitchExtension->Segments[ 0 ] && Track.SwitchExtension->Segments[ 1 ] );
|
||||
}
|
||||
|
||||
bool shaped_blades( TTrack const &Track ) {
|
||||
|
||||
if( cut_rails( Track ) ) {
|
||||
return true;
|
||||
}
|
||||
return track_features::blades
|
||||
&& ( Track.iCategoryFlag & 15 ) == 1
|
||||
&& Track.m_material1 != null_handle
|
||||
&& false == Track.m_editorremoved
|
||||
&& Track.eType == tt_Switch && Track.SwitchExtension && Track.SwitchExtension->m_frogs && Track.SwitchExtension->Segments[ 0 ] && Track.SwitchExtension->Segments[ 1 ];
|
||||
}
|
||||
|
||||
int blade_steps( TTrack const &Track, int const Path ) {
|
||||
|
||||
return static_cast<int>( std::ceil( Track.SwitchExtension->Segments[ Path ]->RaSegCount() * 0.65 ) );
|
||||
@@ -131,7 +153,7 @@ TTrack const *runon_track( TTrack const &Switch, int const Path ) {
|
||||
double blade_runon( TTrack const &Track, int const Side ) {
|
||||
|
||||
auto const *owner { Track.trPrev };
|
||||
if( Track.eType != tt_Normal || Track.Segment == nullptr || owner == nullptr || owner->eType != tt_Switch || false == cut_rails( *owner ) ) {
|
||||
if( Track.eType != tt_Normal || Track.Segment == nullptr || owner == nullptr || owner->eType != tt_Switch || false == shaped_blades( *owner ) ) {
|
||||
return 0.0;
|
||||
}
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
@@ -239,7 +261,8 @@ struct rail_run {
|
||||
double length { 0.0 };
|
||||
};
|
||||
|
||||
std::vector<TTrack *> nearby_rails( TTrack &Track ) {
|
||||
// the tracks with rails around the track: the ones whose rails are cut, or with Whole all of them
|
||||
std::vector<TTrack *> nearby_rails( TTrack &Track, bool const Whole = false ) {
|
||||
|
||||
std::vector<TTrack *> others;
|
||||
auto const sections { simulation::Region->sections( Track.location(), static_cast<float>( Track.radius() + 50.0 ) ) };
|
||||
@@ -249,7 +272,7 @@ std::vector<TTrack *> nearby_rails( TTrack &Track ) {
|
||||
continue;
|
||||
}
|
||||
for( auto *other : cell.m_directories.paths ) {
|
||||
if( other == nullptr || other == &Track || false == cut_rails( *other ) ) {
|
||||
if( other == nullptr || other == &Track || false == ( Whole ? railed( *other ) : cut_rails( *other ) ) ) {
|
||||
continue;
|
||||
}
|
||||
if( glm::length( other->location() - Track.location() ) > other->radius() + Track.radius() + 1.0 ) {
|
||||
@@ -414,11 +437,12 @@ std::vector<rail_crossing> own_crossings( TTrack &Track ) {
|
||||
// with the blades of the other parts left out of the account, as they're yet to be made as short; at the latest short of their throats,
|
||||
// the check rails then cut to begin past the heels
|
||||
// crossings of the rails of the track with the rails of the tracks around, with the blades of switches left out of the account
|
||||
std::vector<rail_crossing> unbladed_crossings( TTrack const &Track ) {
|
||||
// Whole: the rails of the tracks around taken whole too, where they aren't cut
|
||||
std::vector<rail_crossing> unbladed_crossings( TTrack const &Track, bool const Whole = false ) {
|
||||
|
||||
auto &track { const_cast<TTrack &>( Track ) };
|
||||
std::vector<rail_crossing> found;
|
||||
for( auto *other : nearby_rails( track ) ) {
|
||||
for( auto *other : nearby_rails( track, Whole ) ) {
|
||||
for( int otherpath = 0; otherpath < path_count( *other ); ++otherpath ) {
|
||||
rail_run theirs { other, otherpath };
|
||||
theirs.length = path_segment( *other, otherpath ).GetLength();
|
||||
@@ -440,7 +464,8 @@ std::pair<double, double> slip_blade_reach( TTrack const &Track ) {
|
||||
|
||||
auto reach { 1e9 };
|
||||
auto latest { 1e9 };
|
||||
for( auto const &crossing : unbladed_crossings( Track ) ) {
|
||||
// the crossings of the diamond end the blades whether its rails are cut there or laid whole
|
||||
for( auto const &crossing : unbladed_crossings( Track, true ) ) {
|
||||
if( crossing.angle <= middle_angle ) {
|
||||
auto const slope { std::tan( crossing.angle ) };
|
||||
reach = std::min( reach, crossing.at - 0.25 - 0.5 * check_length( slope ) - 0.3 );
|
||||
@@ -831,7 +856,7 @@ track_rails::switch_blade const &TTrack::blade( int const Path ) const {
|
||||
}
|
||||
cached = switch_blade {};
|
||||
auto &result { *cached };
|
||||
if( eType != tt_Switch || false == cut_rails( *this ) || m_profiles.empty() ) {
|
||||
if( eType != tt_Switch || false == shaped_blades( *this ) || m_profiles.empty() ) {
|
||||
return result;
|
||||
}
|
||||
auto const side { blade_side( Path ) };
|
||||
|
||||
@@ -121,6 +121,11 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
|
||||
else {
|
||||
fLength = glm::length(Point1 - Point2);
|
||||
}
|
||||
if( false == std::isfinite( fLength ) ) {
|
||||
|
||||
ErrorLog( "Bad track: spline \"" + pOwner->name() + "\" with no finite length (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
fLength = 0.01;
|
||||
}
|
||||
if (fLength <= 0) {
|
||||
|
||||
ErrorLog( "Bad track: zero length spline \"" + pOwner->name() + "\" (location: " + to_string( glm::dvec3{ Point1 } ) + ")" );
|
||||
@@ -129,7 +134,7 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
|
||||
|
||||
fStoop = std::atan2(Point2.y - Point1.y, fLength); // pochylenie toru prostego, żeby nie liczyć wielokrotnie
|
||||
|
||||
fStep = fNewStep;
|
||||
fStep = ( fNewStep > 0.0 && std::isfinite( fNewStep ) ) ? fNewStep : fLength;
|
||||
// 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 ) {
|
||||
@@ -137,7 +142,7 @@ bool TSegment::Init(glm::dvec3 &NewPoint1, glm::dvec3 NewCPointOut, glm::dvec3 N
|
||||
fStep = fLength / ( 3.0 * Global.SplineFidelity );
|
||||
}
|
||||
// iSegCount = static_cast<int>( std::ceil( fLength / fStep ) ); // potrzebne do VBO
|
||||
iSegCount = pOwner->eType == tt_Switch ? static_cast<int>(6 * Global.SplineFidelity) : static_cast<int>(std::ceil(fLength / fStep)); // potrzebne do VBO
|
||||
iSegCount = pOwner->eType == tt_Switch ? static_cast<int>(6 * Global.SplineFidelity) : static_cast<int>(std::clamp(std::ceil(fLength / fStep), 1.0, 100000.0)); // potrzebne do VBO
|
||||
|
||||
fStep = fLength / iSegCount; // update step to equalize size of individual pieces
|
||||
|
||||
@@ -573,6 +578,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ( jmm1 * ShapePoints[ j ].texture.x + m1 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv1 } );
|
||||
roll_vertex( Output.back(), pos1, parallel1, s - step );
|
||||
}
|
||||
// jeśli jest wskaźnik do tablicy
|
||||
if (p && *p && !j) // to dla pierwszego punktu
|
||||
@@ -591,6 +597,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ( jmm2 * ShapePoints[ j ].texture.x + m2 * ShapePoints[ j + iNumShapePoints ].texture.x ) / texturescale, tv2 } );
|
||||
roll_vertex( Output.back(), pos2, parallel2, s );
|
||||
}
|
||||
// jeśli jest wskaźnik do tablicy
|
||||
// to dla pierwszego punktu
|
||||
@@ -613,6 +620,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv1 } );
|
||||
roll_vertex( Output.back(), pos1, parallel1, s - step );
|
||||
|
||||
pt = parallel2 * ( jmm2 * ( ShapePoints[ j ].position.x - fOffsetX.first ) + m2 * ( ShapePoints[ j ].position.x - fOffsetX.second ) ) + pos2;
|
||||
pt.y += ShapePoints[ j ].position.y;
|
||||
@@ -623,6 +631,7 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
pt,
|
||||
glm::normalize( norm ),
|
||||
glm::vec2 { ShapePoints[ j ].texture.x / texturescale, tv2 } );
|
||||
roll_vertex( Output.back(), pos2, parallel2, s );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,6 +642,25 @@ bool TSegment::RenderLoft( gfx::vertex_array &Output, glm::dvec3 const &Origin,
|
||||
return true;
|
||||
};
|
||||
|
||||
void TSegment::roll_vertex( gfx::basic_vertex &Vertex, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const {
|
||||
if( false == m_baked_roll.has_value() ) {
|
||||
return;
|
||||
}
|
||||
auto const delta { GetRoll( std::clamp( Distance, 0.0, fLength ) ) - *m_baked_roll };
|
||||
if( std::abs( delta ) < 1e-6f ) {
|
||||
return;
|
||||
}
|
||||
auto const c { std::cos( delta ) };
|
||||
auto const s { std::sin( delta ) };
|
||||
// across the path and up turned the way the profiles are turned by the roll, along the path as it was
|
||||
auto const turn = [&]( glm::vec3 const &Vector ) {
|
||||
auto const across { glm::dot( Vector, Parallel ) };
|
||||
auto const along { Vector - Parallel * across - glm::vec3 { 0.f, Vector.y, 0.f } };
|
||||
return along + Parallel * ( across * c + Vector.y * s ) + glm::vec3 { 0.f, -across * s + Vector.y * c, 0.f }; };
|
||||
Vertex.position = Position + turn( Vertex.position - Position );
|
||||
Vertex.normal = turn( Vertex.normal );
|
||||
}
|
||||
|
||||
bool TSegment::RenderLoftSteps( gfx::vertex_array &Output, glm::dvec3 const &Origin, gfx::vertex_array const &ShapePoints, double fTextureLength, int const Steps ) const
|
||||
{
|
||||
if( fTsBuffer.empty() || Steps < 1 || fLength <= 0.0 )
|
||||
@@ -670,7 +698,8 @@ bool TSegment::RenderLoftSteps( gfx::vertex_array &Output, glm::dvec3 const &Ori
|
||||
point.y += rest * from.position.y + Share * to.position.y;
|
||||
auto normal { ( rest * from.normal.x + Share * to.normal.x ) * Parallel };
|
||||
normal.y += rest * from.normal.y + Share * to.normal.y;
|
||||
Output.emplace_back( point, glm::normalize( normal ), glm::vec2 { rest * from.texture.x + Share * to.texture.x, V } ); };
|
||||
Output.emplace_back( point, glm::normalize( normal ), glm::vec2 { rest * from.texture.x + Share * to.texture.x, V } );
|
||||
roll_vertex( Output.back(), Position, Parallel, Share * fLength ); };
|
||||
|
||||
glm::vec3 pos1, pos2, parallel1, parallel2;
|
||||
station( 0, pos1, parallel1 );
|
||||
@@ -894,6 +923,11 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
auto const onwall { paired ? ( false == open( partner ) && clamped( partner ) == side ) : moved == count };
|
||||
if( onwall ) {
|
||||
wall = ( side > 0 ? outerwall : innerwall );
|
||||
// a face of the profile squeezed onto the wall from the other side of the rail keeps facing that side: the thin plate a
|
||||
// planed blade gets to near its tip is lit from the middle of the track as its face there, not as the one against the stock rail
|
||||
if( static_cast<float>( Span.side * side ) * ShapePoints[ j ].normal.x < 0.f ) {
|
||||
wall = -wall;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( drop > 0.0 && shape.position.y > Span.head.x && Span.head.y > Span.head.x ) {
|
||||
@@ -912,6 +946,9 @@ bool TSegment::RenderLoftSpan( gfx::vertex_array &Output, glm::dvec3 const &Orig
|
||||
Ring.emplace_back( pt, glm::normalize( norm ), glm::vec2{ shape.texture.x, 0.f } );
|
||||
Wear.push_back( Span.rampwidth != 0.0 ? static_cast<float>( std::clamp( ( Span.rampwidth > 0.0 ? outside - worn : worn - outside ) / std::abs( Span.rampwidth ) + 1.0, 0.0, 1.0 ) ) : 1.f );
|
||||
}
|
||||
for( auto &vertex : Ring ) {
|
||||
roll_vertex( vertex, position, parallel, Distance );
|
||||
}
|
||||
};
|
||||
|
||||
auto const texturelength { static_cast<float>( Span.texturelength ) };
|
||||
|
||||
@@ -102,6 +102,9 @@ class TSegment
|
||||
std::vector<double> m_starts; // distance from Point1 to the start of each part
|
||||
std::optional<std::pair<glm::dvec3, glm::dvec3>> m_joints[ 2 ];
|
||||
double m_dense { 0.0 };
|
||||
// a switch makes the profiles of its rails and its bed at the mean of the rolls of its paths: lofted along a path, they're turned
|
||||
// from it to the roll of the path there, so a switch on a cant ramp follows it; none for the other paths
|
||||
std::optional<float> m_baked_roll;
|
||||
|
||||
glm::dvec3 GetFirstDerivative(double const fTime) const;
|
||||
double RombergIntegral(double const fA, double const fB) const;
|
||||
@@ -111,6 +114,8 @@ class TSegment
|
||||
glm::dvec3 RaInterpolate(double const t) const;
|
||||
glm::dvec3 RaInterpolate0(double const t) const;
|
||||
std::size_t piece_at(double const s) const;
|
||||
// the vertex of a profile lofted at the point and across the path there, turned from the baked roll to the one of the path at the distance
|
||||
void roll_vertex( gfx::basic_vertex &Vertex, glm::vec3 const &Position, glm::vec3 const &Parallel, double const Distance ) const;
|
||||
|
||||
public:
|
||||
bool bCurve = false;
|
||||
@@ -200,6 +205,9 @@ public:
|
||||
void
|
||||
set_dense( double const Distance ) {
|
||||
m_dense = Distance; }
|
||||
void
|
||||
set_baked_roll( std::optional<float> const Roll ) {
|
||||
m_baked_roll = Roll; }
|
||||
/*
|
||||
void
|
||||
Render();
|
||||
|
||||
128
world/Track.cpp
128
world/Track.cpp
@@ -60,8 +60,10 @@ void init_switch_piece( TSegment &Segment, segment_data const &Piece, bool const
|
||||
p1.y += 0.18;
|
||||
p2.y += 0.18;
|
||||
}
|
||||
if( glm::length2( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ) < sq( 0.02 )
|
||||
|| glm::length2( ( p1 + p2 + p2 ) / 3.0 - p2 - cp2 ) < sq( 0.02 ) ) {
|
||||
// one with its radius given is a curve however gently it bends, as a short path bent with the curve it's laid into
|
||||
if( Piece.radius == 0.f
|
||||
&& ( glm::length2( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ) < sq( 0.02 )
|
||||
|| glm::length2( ( p1 + p2 + p2 ) / 3.0 - p2 - cp2 ) < sq( 0.02 ) ) ) {
|
||||
cp1 = cp2 = glm::dvec3( 0, 0, 0 );
|
||||
}
|
||||
auto const straight { cp1 == glm::dvec3() && cp2 == glm::dvec3() };
|
||||
@@ -426,6 +428,7 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
std::string str;
|
||||
size_t i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie
|
||||
std::string token;
|
||||
bool tributary{false};
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> str; // typ toru
|
||||
@@ -467,11 +470,17 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
}
|
||||
else if (str == "tributary")
|
||||
{
|
||||
eType = tt_Tributary;
|
||||
ErrorLog("Bad track: type \"tributary\" of track \"" + m_name + "\" in file \"" + parser->Name() + "\" (line " + std::to_string(parser->Line()) + ") isn't supported, loaded as a river with its first path");
|
||||
eType = tt_Normal;
|
||||
iCategoryFlag = 4;
|
||||
tributary = true;
|
||||
}
|
||||
else
|
||||
eType = tt_Unknown;
|
||||
{
|
||||
ErrorLog("Bad track: unknown type \"" + str + "\" of track \"" + m_name + "\" in file \"" + parser->Name() + "\" (line " + std::to_string(parser->Line()) + "), loaded as a normal track");
|
||||
eType = tt_Normal;
|
||||
iCategoryFlag = 1;
|
||||
}
|
||||
if (Global.iWriteLogEnabled & 4)
|
||||
WriteLog(str);
|
||||
parser->getTokens(4);
|
||||
@@ -544,6 +553,10 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
// all subtypes contain at least one path
|
||||
m_paths.emplace_back();
|
||||
m_paths.back().deserialize( *parser, pOrigin );
|
||||
if( tributary ) {
|
||||
segment_data ignored;
|
||||
ignored.deserialize( *parser, pOrigin );
|
||||
}
|
||||
switch( eType ) {
|
||||
case tt_Switch:
|
||||
case tt_Cross:
|
||||
@@ -842,9 +855,12 @@ void TTrack::init_segments( bool const Initial ) {
|
||||
}
|
||||
|
||||
// length2 is better than length for comparing because it does not require sqrt function
|
||||
if( glm::length2((p1 + p1 + p2) / 3.0 - p1 - cp1) < sq(0.02)
|
||||
|| glm::length2((p1 + p2 + p2) / 3.0 - p2 + cp1) < sq(0.02) ) {
|
||||
// "prostowanie" prostych z kontrolnymi, dokładność 2cm
|
||||
// "prostowanie" prostych z kontrolnymi, dokładność 2cm: a straight only where both control vectors lie along it, or aren't
|
||||
// given; one of them moved off it, the other one left where a straight has it, makes a curve. One with its radius given is a
|
||||
// curve however gently it bends, as a short path bent with the curve it's laid into
|
||||
auto const startalong { cp1 == glm::dvec3() || glm::length2( ( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ) < sq( 0.02 ) };
|
||||
auto const endalong { cp2 == glm::dvec3() || glm::length2( ( p1 + p2 + p2 ) / 3.0 - p2 - cp2 ) < sq( 0.02 ) };
|
||||
if( startalong && endalong && fRadius == 0 ) {
|
||||
cp1 = cp2 = glm::dvec3(0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -936,8 +952,8 @@ void TTrack::init_segments( bool const Initial ) {
|
||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||
}
|
||||
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( eType != tt_Cross && fRadiusTable[ 0 ] == 0 ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne; a path with its radius given is a curve however gently it bends
|
||||
// length2 is better than length for comparing because it does not require sqrt function
|
||||
if( glm::length2(( p1 + p1 + p2 ) / 3.0 - p1 - cp1 ) < sq(0.02)
|
||||
|| glm::length2(( p1 + p2 + p2 ) / 3.0 - p2 + cp1 ) < sq(0.02) ) {
|
||||
@@ -1001,8 +1017,8 @@ void TTrack::init_segments( bool const Initial ) {
|
||||
// na przechyłce doliczyć jeszcze pół przechyłki?
|
||||
}
|
||||
|
||||
if( eType != tt_Cross ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne
|
||||
if( eType != tt_Cross && fRadiusTable[ 1 ] == 0 ) {
|
||||
// dla skrzyżowań muszą być podane kontrolne; a path with its radius given is a curve however gently it bends
|
||||
// length2 is better than length for comparing because it does not require sqrt function
|
||||
if( glm::length2((p3 + p3 + p4) / 3.0 - p3 - cp3) < sq(0.02)
|
||||
|| glm::length2((p3 + p4 + p4) / 3.0 - p4 + cp3) < sq(0.02) ) {
|
||||
@@ -1092,6 +1108,13 @@ void TTrack::init_segments( bool const Initial ) {
|
||||
fTexHeightOffset = texheightoffset;
|
||||
SwitchExtension->Segments[ index ]->InitChain( std::move( chain ) );
|
||||
}
|
||||
// the profiles of the switch are made at the mean of the rolls of its paths; lofted, they're turned from it to the roll of
|
||||
// each path along it, so a switch on a cant ramp follows the ramp to its ends
|
||||
float mean1, mean2;
|
||||
profile_rolls( mean1, mean2 );
|
||||
for( std::size_t index = 0; index < 2; ++index ) {
|
||||
SwitchExtension->Segments[ index ]->set_baked_roll( mean1 );
|
||||
}
|
||||
}
|
||||
|
||||
if( Initial ) {
|
||||
@@ -1488,12 +1511,27 @@ glm::vec3 TTrack::get_nearest_point(const glm::dvec3 &point) const
|
||||
void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
track_rails::forget();
|
||||
auto const erase = [ this ]( gfx::geometry_handle const &Chunk ) {
|
||||
if( SwitchExtension
|
||||
&& std::any_of( SwitchExtension->m_nosechunks.begin(), SwitchExtension->m_nosechunks.end(), [ & ]( auto const &Pooled ) { return Pooled.handle == Chunk; } ) ) {
|
||||
return;
|
||||
}
|
||||
GfxRenderer->Erase( Chunk );
|
||||
};
|
||||
for( auto const *geometry : { &Geometry1, &Geometry2, &GeometryCut1, &GeometryCut2 } ) {
|
||||
std::for_each( geometry->begin(), geometry->end(), erase );
|
||||
}
|
||||
for( auto const &tread : GeometryTreads ) {
|
||||
std::for_each( tread.geometry.begin(), tread.geometry.end(), erase );
|
||||
std::for_each( tread.cuts.begin(), tread.cuts.end(), erase );
|
||||
}
|
||||
Geometry1.clear();
|
||||
Geometry2.clear();
|
||||
GeometryCut1.clear();
|
||||
GeometryCut2.clear();
|
||||
GeometryTreads.clear();
|
||||
if( SwitchExtension ) {
|
||||
erase( SwitchExtension->Geometry3 );
|
||||
SwitchExtension->Geometry3 = gfx::geometry_handle{};
|
||||
}
|
||||
m_sleeper_local_transforms.clear();
|
||||
@@ -1640,7 +1678,13 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
continue;
|
||||
}
|
||||
vertices.clear(); // reuse the scratchpad
|
||||
Segment->RenderLoft( vertices, m_origin, profile, iTrapezoid > 0, texturelength );
|
||||
// the rail starts behind the heel of a blade running on into the track from the switch before it
|
||||
if( auto const runon { eType == tt_Normal && iTrapezoid == 0 ? track_rails::blade_runon( *this, side ) : 0.0 }; runon > 0.0 ) {
|
||||
Segment->RenderLoftSpan( vertices, m_origin, profile, { .side = side, .halfwidth = 0.5f * std::abs( fTrackWidth ), .texturelength = texturelength, .from = runon, .to = Segment->GetLength() } );
|
||||
}
|
||||
else {
|
||||
Segment->RenderLoft( vertices, m_origin, profile, iTrapezoid > 0, texturelength );
|
||||
}
|
||||
if( open ) {
|
||||
cut_faces( vertices, nnumPts, trPrev == nullptr, trNext == nullptr, GeometryCut1 );
|
||||
}
|
||||
@@ -2014,6 +2058,59 @@ bool TTrack::SetConnections(int i)
|
||||
return false;
|
||||
}
|
||||
|
||||
void TTrack::join_switches()
|
||||
{
|
||||
if( eType != tt_Switch || SwitchExtension == nullptr || simulation::Region == nullptr ) {
|
||||
return;
|
||||
}
|
||||
// the ends of the paths as the codes of the track joined to them have them: 0 the start of a switch, where both paths begin, 1 the end of
|
||||
// its first path, 3 the end of its second one; a vehicle going on onto a start keeps its direction, onto an end it turns
|
||||
auto const code = []( int const Endpoint ) { return Endpoint == 3 ? 1 : Endpoint == 5 ? 3 : 0; };
|
||||
// the paths of the switch joined to its neighbours as it's set, as Switch() takes them
|
||||
auto const bind = []( TTrack &Switch ) {
|
||||
auto const &extension { *Switch.SwitchExtension };
|
||||
auto const state { extension.CurrentIndex & 1 };
|
||||
Switch.trNext = extension.pNexts[ state ];
|
||||
Switch.trPrev = extension.pPrevs[ state ];
|
||||
Switch.iNextDirection = extension.iNextDirection[ state ];
|
||||
Switch.iPrevDirection = extension.iPrevDirection[ state ];
|
||||
};
|
||||
auto &own { *SwitchExtension };
|
||||
for( int path = 0; path < 2; ++path ) {
|
||||
for( int end = 0; end < 2; ++end ) {
|
||||
if( ( end ? own.pNexts[ path ] : own.pPrevs[ path ] ) != nullptr || own.Segments[ path ] == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
auto const point { end ? own.Segments[ path ]->FastGetPoint_1() : own.Segments[ path ]->FastGetPoint_0() };
|
||||
auto const [ other, endpoint ] { simulation::Region->find_path( point, this ) };
|
||||
if( other == nullptr || other == this || other->eType != tt_Switch || other->SwitchExtension == nullptr || endpoint < 2 || endpoint > 5 ) {
|
||||
continue;
|
||||
}
|
||||
auto &theirs { *other->SwitchExtension };
|
||||
if( end == 0 ) {
|
||||
own.pPrevs[ 0 ] = own.pPrevs[ 1 ] = other;
|
||||
own.iPrevDirection[ 0 ] = own.iPrevDirection[ 1 ] = code( endpoint );
|
||||
}
|
||||
else {
|
||||
own.pNexts[ path ] = other;
|
||||
own.iNextDirection[ path ] = code( endpoint );
|
||||
}
|
||||
auto const ours { end == 0 ? 0 : path ? 3 : 1 };
|
||||
if( endpoint == 2 || endpoint == 4 ) {
|
||||
theirs.pPrevs[ 0 ] = theirs.pPrevs[ 1 ] = this;
|
||||
theirs.iPrevDirection[ 0 ] = theirs.iPrevDirection[ 1 ] = ours;
|
||||
}
|
||||
else {
|
||||
auto const theirpath { endpoint == 5 ? 1 : 0 };
|
||||
theirs.pNexts[ theirpath ] = this;
|
||||
theirs.iNextDirection[ theirpath ] = ours;
|
||||
}
|
||||
bind( *other );
|
||||
}
|
||||
}
|
||||
bind( *this );
|
||||
}
|
||||
|
||||
bool TTrack::Switch(int i, float const t, float const d)
|
||||
{ // przełączenie torów z uruchomieniem animacji
|
||||
if (SwitchExtension) // tory przełączalne mają doklejkę
|
||||
@@ -3954,6 +4051,13 @@ path_table::InitTracks() {
|
||||
}
|
||||
}
|
||||
|
||||
// the plain tracks are joined to the switches above, a switch right after another one only here, once they are
|
||||
for( auto *track : m_items ) {
|
||||
if( track->eType == tt_Switch ) {
|
||||
track->join_switches();
|
||||
}
|
||||
}
|
||||
|
||||
if( Global.CreateSwitchTrackbeds ) {
|
||||
// do this after all connections are established, otherwise missing switch connections
|
||||
// may prevent us from obtaining texture data for basic track from 'across' a switch
|
||||
|
||||
@@ -324,6 +324,9 @@ public:
|
||||
material_handle rail_material( int const Path ) const;
|
||||
glm::vec2 tread_band() const;
|
||||
bool SetConnections(int i);
|
||||
// joins the free ends of the switch to the free ends of other switches in the same points, which the plain tracks joined to switches
|
||||
// leave out: a switch right after another one, at the end of either path of it, two facing at their starts or meeting at their ends
|
||||
void join_switches();
|
||||
bool Switch(int i, float const t = -1.f, float const d = -1.f);
|
||||
bool SwitchForced(int i, TDynamicObject *o);
|
||||
int CrossSegment(int from, int into);
|
||||
|
||||
@@ -17,5 +17,8 @@ namespace track_features {
|
||||
bool constexpr crossings { true };
|
||||
// the 3D sleepers and switch timbers of sleepers3d; off, the tracks keep their ballast whatever eu07.ini sets
|
||||
bool constexpr sleepers { true };
|
||||
// the blades of the switches with the key frogs shaped as their templates have them, from the tip their planed nose ends at to the heel,
|
||||
// with the rails left whole where the crossings are off; off with the crossings too, they're laid from the start of the switch as before
|
||||
bool constexpr blades { true };
|
||||
|
||||
} // namespace track_features
|
||||
|
||||
@@ -33,6 +33,9 @@ double check_length( double const Slope );
|
||||
double movable_nose_length( double const Slope );
|
||||
// the rails of the track are cut where they cross other rails: plain tracks, and switches whose frog is made from the rails
|
||||
bool cut_rails( TTrack const &Track );
|
||||
// the blades of the switch are shaped from the tip to the heel: with the rails cut, or alone where only the blades are on, but for the
|
||||
// switches of a double slip, whose blades end short of crossings found only with the rails cut
|
||||
bool shaped_blades( TTrack const &Track );
|
||||
int blade_steps( TTrack const &Track, int const Path );
|
||||
double blade_length( TTrack const &Track, int const Path );
|
||||
// the plain track a path of a switch goes on into at its end, laid the same way, which the blade of the path may run on into
|
||||
|
||||
Reference in New Issue
Block a user