mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-29 05:47:28 +01:00
perf(sleepers): the rails of each track for the fastenings worked out once and kept until its geometry is made again, it goes far or the crossings change, not again for every track laid around it; the fastenings laid only out to 30 m past where they're drawn, the tracks further out keeping their beams to lay them on as they come near; out past 50 m the tracks laid while the laying in a frame took under 2 ms, the rest in the frames after
This commit is contained in:
@@ -6203,6 +6203,12 @@ void opengl46_renderer::Render_Timbers( scene::basic_cell::path_sequence::const_
|
||||
m_timbersweepframe = m_framestamp;
|
||||
track_sleepers::release_far( camera, range + 600.0 );
|
||||
}
|
||||
if( m_timberlayframe != m_framestamp ) {
|
||||
m_timberlayframe = m_framestamp;
|
||||
m_timberlaying = 0.0;
|
||||
}
|
||||
// the fastenings laid out to a little past where they're drawn
|
||||
auto const fasteningrange = std::min( static_cast<double>( Global.SleeperDistance ), track_sleepers::fastening_range ) + track_sleepers::fastening_lead;
|
||||
glm::mat4 const originmodelview = OpenGLMatrices.data( GL_MODELVIEW );
|
||||
for( auto &bucket : m_timberbuckets ) {
|
||||
bucket.instances.clear();
|
||||
@@ -6243,15 +6249,28 @@ void opengl46_renderer::Render_Timbers( scene::basic_cell::path_sequence::const_
|
||||
for( auto first { First }; first != Last; ++first ) {
|
||||
auto *track = *first;
|
||||
if( false == track->m_visible || false == track->m_sleepers3d.active ) { continue; }
|
||||
if( glm::length( track->location() - camera ) > range + track->radius() ) {
|
||||
auto const trackdistance = glm::length( track->location() - camera );
|
||||
if( trackdistance > range + track->radius() ) {
|
||||
// worked out ahead, in the background, before it comes in range
|
||||
if( false == shadows && track->m_sleepers3d.dirty && glm::length( track->location() - camera ) < range + track->radius() + 300.0 ) {
|
||||
if( false == shadows && track->m_sleepers3d.dirty && trackdistance < range + track->radius() + 300.0 ) {
|
||||
track_sleepers::prefetch( *track );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if( track->m_sleepers3d.dirty ) {
|
||||
track_sleepers::lay( *track );
|
||||
auto const fastened = ( trackdistance < fasteningrange + track->radius() );
|
||||
if( track->m_sleepers3d.dirty || ( fastened && false == track->m_sleepers3d.fastened ) ) {
|
||||
// the nearest at once, the others while the frame has the time, the cells nearest coming first; till then a track draws
|
||||
// what it had
|
||||
if( trackdistance < track_sleepers::lay_near + track->radius() || m_timberlaying < track_sleepers::lay_budget ) {
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
if( track->m_sleepers3d.dirty ) {
|
||||
track_sleepers::lay( *track, fastened );
|
||||
}
|
||||
else {
|
||||
track_sleepers::fasten( *track );
|
||||
}
|
||||
m_timberlaying += std::chrono::duration<double, std::milli>( std::chrono::steady_clock::now() - start ).count();
|
||||
}
|
||||
}
|
||||
auto const &laid = track->m_sleepers3d;
|
||||
if( laid.timbers == nullptr ) { continue; }
|
||||
|
||||
@@ -610,6 +610,8 @@ class opengl46_renderer : public gfx_renderer {
|
||||
|
||||
unsigned int m_framestamp; // id of currently rendered gfx frame
|
||||
unsigned int m_timbersweepframe { 0 }; // the frame the beams of the tracks far away were last let go in
|
||||
unsigned int m_timberlayframe { 0 }; // the frame the time spent laying the beams is counted for
|
||||
double m_timberlaying { 0.0 }; // in ms
|
||||
float m_framerate;
|
||||
double m_updateaccumulator{0.0};
|
||||
std::string m_debugtimestext;
|
||||
|
||||
@@ -52,90 +52,119 @@ fastened_rails::fastened_rails( TTrack &Track ) {
|
||||
if( bedded( *Other ) && std::find( tracks.begin(), tracks.end(), Other ) == tracks.end() ) {
|
||||
tracks.push_back( Other );
|
||||
} } );
|
||||
auto &kept { fastened_rails::kept() };
|
||||
for( auto *track : tracks ) {
|
||||
auto const size { track->rail_dimensions() };
|
||||
auto const middle { 0.5 * std::abs( track->fTrackWidth ) + size.web };
|
||||
auto const cut { track_rails::cut_rails( *track ) };
|
||||
auto const switched { track->eType == tt_Switch && track->SwitchExtension != nullptr };
|
||||
auto const rise { wing_rise( *track ) };
|
||||
// what the rail is along the path: a blade, the stock rail of a blade, checked
|
||||
auto const add = [&]( rail &&Line, int const Path, int const Side ) {
|
||||
if( switched ) {
|
||||
if( auto const heel { blade_heel( *track, Path, Side ) }; heel > 0.0 ) {
|
||||
Line.blade = { 0.0, heel };
|
||||
}
|
||||
Line.stock = stock_stretch( *track, Path, Side );
|
||||
auto &rails { kept[ track ] };
|
||||
if( rails == nullptr ) {
|
||||
rails = std::make_shared<std::vector<rail> const>( rails_of( *track ) );
|
||||
}
|
||||
m_kept.push_back( rails );
|
||||
m_rails.insert( m_rails.end(), rails->begin(), rails->end() );
|
||||
}
|
||||
}
|
||||
|
||||
fastened_rails::kept_rails &fastened_rails::kept() {
|
||||
|
||||
static kept_rails tracks;
|
||||
static unsigned int stamp { 0 };
|
||||
if( stamp != track_rails::memo_stamp() ) {
|
||||
tracks.clear();
|
||||
stamp = track_rails::memo_stamp();
|
||||
}
|
||||
return tracks;
|
||||
}
|
||||
|
||||
void forget_rails( TTrack const &Track ) {
|
||||
|
||||
fastened_rails::kept().erase( &Track );
|
||||
}
|
||||
|
||||
std::vector<fastened_rails::rail> fastened_rails::rails_of( TTrack &Track ) {
|
||||
|
||||
std::vector<rail> result;
|
||||
auto const size { Track.rail_dimensions() };
|
||||
auto const middle { 0.5 * std::abs( Track.fTrackWidth ) + size.web };
|
||||
auto const cut { track_rails::cut_rails( Track ) };
|
||||
auto const switched { Track.eType == tt_Switch && Track.SwitchExtension != nullptr };
|
||||
auto const rise { wing_rise( Track ) };
|
||||
// what the rail is along the path: a blade, the stock rail of a blade, checked
|
||||
auto const add = [&]( rail &&Line, int const Path, int const Side ) {
|
||||
if( switched ) {
|
||||
if( auto const heel { blade_heel( Track, Path, Side ) }; heel > 0.0 ) {
|
||||
Line.blade = { 0.0, heel };
|
||||
}
|
||||
if( cut ) {
|
||||
for( auto const &check : track_rails::rail_checks( *track )[ Path ][ Side > 0 ? 1 : 0 ] ) {
|
||||
Line.checks.emplace_back( check.from, check.to );
|
||||
}
|
||||
Line.guards = track->m_railguards[ Path ][ Side > 0 ? 1 : 0 ];
|
||||
Line.stock = stock_stretch( Track, Path, Side );
|
||||
}
|
||||
if( cut ) {
|
||||
for( auto const &check : track_rails::rail_checks( Track )[ Path ][ Side > 0 ? 1 : 0 ] ) {
|
||||
Line.checks.emplace_back( check.from, check.to );
|
||||
}
|
||||
m_rails.emplace_back( std::move( Line ) ); };
|
||||
// the rail of the side of the path from and to along it, by points the given way out from the middle of the path
|
||||
auto const sampled = [&]( int const Path, int const Side, double const From, double const To, double const Middle, knots::line const &Offsets ) {
|
||||
auto const *segment { path_segment( *track, Path ) };
|
||||
auto const count { std::max( 1, static_cast<int>( std::ceil( ( To - From ) / fastening_step ) ) ) };
|
||||
rail line;
|
||||
line.track = track;
|
||||
line.path = Path;
|
||||
line.side = Side;
|
||||
line.foot = size.web - size.low;
|
||||
line.low = glm::dvec2 { std::numeric_limits<double>::max() };
|
||||
line.high = glm::dvec2 { std::numeric_limits<double>::lowest() };
|
||||
for( int step = 0; step <= count; ++step ) {
|
||||
auto const distance { From + ( To - From ) * step / count };
|
||||
glm::dvec3 point, across;
|
||||
segment->plan_frame( distance, point, across );
|
||||
auto const flat { plan( across ) };
|
||||
auto const inward { glm::length( flat ) > 1e-9 ? glm::normalize( flat ) * static_cast<double>( -Side ) : glm::dvec2 { 1.0, 0.0 } };
|
||||
auto const position { plan( point ) - inward * ( Middle + knots::sample( Offsets, distance, 0.0 ) ) };
|
||||
line.points.push_back( position );
|
||||
line.heights.push_back( point.y );
|
||||
line.inward.push_back( inward );
|
||||
line.distances.push_back( distance );
|
||||
line.low = glm::min( line.low, position );
|
||||
line.high = glm::max( line.high, position );
|
||||
}
|
||||
return line; };
|
||||
for( int path = 0; path < path_count( *track ); ++path ) {
|
||||
auto const *segment { path_segment( *track, path ) };
|
||||
if( segment == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
auto const length { segment->GetLength() };
|
||||
for( auto const side : { -1, 1 } ) {
|
||||
// the rail in its parts between the cuts at the crossings, as they're laid: a wing rail bent out from the path; on over the
|
||||
// gap at an obtuse crossing, where its check rail lies
|
||||
auto cuts { cut ? track->m_railplans[ path ][ side > 0 ].cuts : std::vector<track_rails::rail_cut> {} };
|
||||
std::stable_sort( cuts.begin(), cuts.end(), []( track_rails::rail_cut const &A, track_rails::rail_cut const &B ) { return A.at < B.at; } );
|
||||
for( std::size_t part = 0; part <= cuts.size(); ++part ) {
|
||||
auto const *before { part > 0 ? &cuts[ part - 1 ] : nullptr };
|
||||
auto const *after { part < cuts.size() ? &cuts[ part ] : nullptr };
|
||||
auto const from { std::max( 0.0, before != nullptr ? before->start : 0.0 ) };
|
||||
auto const to { std::min( length, after != nullptr ? std::max( after->end, after->start ) : length ) };
|
||||
if( to - from < fastening_merge ) {
|
||||
continue;
|
||||
}
|
||||
auto line { sampled( path, side, from, to, middle, track_rails::part_offsets( before, after ) ) };
|
||||
line.rises = track_rails::part_rises( rise > 0.0 ? track_rails::wing_shares( before, after, stock_stretch( *track, path, side ) ) : knots::line {}, rise, blade_heel( *track, path, side ) );
|
||||
add( std::move( line ), path, side );
|
||||
Line.guards = Track.m_railguards[ Path ][ Side > 0 ? 1 : 0 ];
|
||||
}
|
||||
result.emplace_back( std::move( Line ) ); };
|
||||
// the rail of the side of the path from and to along it, by points the given way out from the middle of the path
|
||||
auto const sampled = [&]( int const Path, int const Side, double const From, double const To, double const Middle, knots::line const &Offsets ) {
|
||||
auto const *segment { path_segment( Track, Path ) };
|
||||
auto const count { std::max( 1, static_cast<int>( std::ceil( ( To - From ) / fastening_step ) ) ) };
|
||||
rail line;
|
||||
line.track = &Track;
|
||||
line.path = Path;
|
||||
line.side = Side;
|
||||
line.foot = size.web - size.low;
|
||||
line.low = glm::dvec2 { std::numeric_limits<double>::max() };
|
||||
line.high = glm::dvec2 { std::numeric_limits<double>::lowest() };
|
||||
for( int step = 0; step <= count; ++step ) {
|
||||
auto const distance { From + ( To - From ) * step / count };
|
||||
glm::dvec3 point, across;
|
||||
segment->plan_frame( distance, point, across );
|
||||
auto const flat { plan( across ) };
|
||||
auto const inward { glm::length( flat ) > 1e-9 ? glm::normalize( flat ) * static_cast<double>( -Side ) : glm::dvec2 { 1.0, 0.0 } };
|
||||
auto const position { plan( point ) - inward * ( Middle + knots::sample( Offsets, distance, 0.0 ) ) };
|
||||
line.points.push_back( position );
|
||||
line.heights.push_back( point.y );
|
||||
line.inward.push_back( inward );
|
||||
line.distances.push_back( distance );
|
||||
line.low = glm::min( line.low, position );
|
||||
line.high = glm::max( line.high, position );
|
||||
}
|
||||
return line; };
|
||||
for( int path = 0; path < path_count( Track ); ++path ) {
|
||||
auto const *segment { path_segment( Track, path ) };
|
||||
if( segment == nullptr ) {
|
||||
continue;
|
||||
}
|
||||
auto const length { segment->GetLength() };
|
||||
for( auto const side : { -1, 1 } ) {
|
||||
// the rail in its parts between the cuts at the crossings, as they're laid: a wing rail bent out from the path; on over the
|
||||
// gap at an obtuse crossing, where its check rail lies
|
||||
auto cuts { cut ? Track.m_railplans[ path ][ side > 0 ].cuts : std::vector<track_rails::rail_cut> {} };
|
||||
std::stable_sort( cuts.begin(), cuts.end(), []( track_rails::rail_cut const &A, track_rails::rail_cut const &B ) { return A.at < B.at; } );
|
||||
for( std::size_t part = 0; part <= cuts.size(); ++part ) {
|
||||
auto const *before { part > 0 ? &cuts[ part - 1 ] : nullptr };
|
||||
auto const *after { part < cuts.size() ? &cuts[ part ] : nullptr };
|
||||
auto const from { std::max( 0.0, before != nullptr ? before->start : 0.0 ) };
|
||||
auto const to { std::min( length, after != nullptr ? std::max( after->end, after->start ) : length ) };
|
||||
if( to - from < fastening_merge ) {
|
||||
continue;
|
||||
}
|
||||
// the guard rails of the crossings at wide angles inside the rail, the flangeway from it
|
||||
for( auto const &guard : cut ? track->m_railguards[ path ][ side > 0 ] : std::vector<glm::dvec2> {} ) {
|
||||
auto const from { std::max( 0.0, guard.x ) };
|
||||
auto const to { std::min( length, guard.y ) };
|
||||
if( to - from < fastening_merge ) {
|
||||
continue;
|
||||
}
|
||||
auto line { sampled( path, side, from, to, middle - ( track_rails::flangeway + size.head ), {} ) };
|
||||
line.guard = true;
|
||||
m_rails.emplace_back( std::move( line ) );
|
||||
auto line { sampled( path, side, from, to, middle, track_rails::part_offsets( before, after ) ) };
|
||||
line.rises = track_rails::part_rises( rise > 0.0 ? track_rails::wing_shares( before, after, stock_stretch( Track, path, side ) ) : knots::line {}, rise, blade_heel( Track, path, side ) );
|
||||
add( std::move( line ), path, side );
|
||||
}
|
||||
// the guard rails of the crossings at wide angles inside the rail, the flangeway from it
|
||||
for( auto const &guard : cut ? Track.m_railguards[ path ][ side > 0 ] : std::vector<glm::dvec2> {} ) {
|
||||
auto const from { std::max( 0.0, guard.x ) };
|
||||
auto const to { std::min( length, guard.y ) };
|
||||
if( to - from < fastening_merge ) {
|
||||
continue;
|
||||
}
|
||||
auto line { sampled( path, side, from, to, middle - ( track_rails::flangeway + size.head ), {} ) };
|
||||
line.guard = true;
|
||||
result.emplace_back( std::move( line ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<fastened_rails::hit> fastened_rails::rails_on( beam const &Beam ) const {
|
||||
@@ -150,7 +179,7 @@ std::vector<fastened_rails::hit> fastened_rails::rails_on( beam const &Beam ) co
|
||||
auto const low { glm::min( start, plan( Beam.to ) ) };
|
||||
auto const high { glm::max( start, plan( Beam.to ) ) };
|
||||
std::vector<hit> hits;
|
||||
for( auto const &line : m_rails ) {
|
||||
for( rail const &line : m_rails ) {
|
||||
if( line.high.x < low.x || line.low.x > high.x || line.high.y < low.y || line.low.y > high.y ) {
|
||||
continue;
|
||||
}
|
||||
@@ -387,7 +416,7 @@ void fastened_rails::along( std::vector<fastening> &Fastenings, beam const &Beam
|
||||
double to;
|
||||
};
|
||||
std::vector<stretch> stretches;
|
||||
for( auto const &line : m_rails ) {
|
||||
for( rail const &line : m_rails ) {
|
||||
// a guard rail along the timber lies in the fastening of its running rail
|
||||
if( line.guard || line.high.x < low.x || line.low.x > high.x || line.high.y < low.y || line.low.y > high.y ) {
|
||||
continue;
|
||||
|
||||
@@ -10,7 +10,10 @@ http://mozilla.org/MPL/2.0/.
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
@@ -92,6 +95,13 @@ private:
|
||||
role at( double const Distance ) const;
|
||||
bool guarded( double const Distance ) const;
|
||||
};
|
||||
// the rails of each track, worked out as the first track around it is laid and kept until it's laid anew or goes far, or
|
||||
// the crossings change
|
||||
using kept_rails = std::unordered_map<TTrack const *, std::shared_ptr<std::vector<rail> const>>;
|
||||
static kept_rails &kept();
|
||||
friend void forget_rails( TTrack const &Track );
|
||||
// the rails of the track, in their parts between the cuts, and its guard rails
|
||||
static std::vector<rail> rails_of( TTrack &Track );
|
||||
|
||||
// the rails lying on the timber, in the order along it, one where several lie on one another, but the blades
|
||||
std::vector<hit> rails_on( beam const &Beam ) const;
|
||||
@@ -106,7 +116,8 @@ private:
|
||||
// across leave, on the timber with the rail over its middle or over its side toward the next one
|
||||
void along( std::vector<fastening> &Fastenings, beam const &Beam, beam_model const &Model ) const;
|
||||
|
||||
std::vector<rail> m_rails;
|
||||
std::vector<std::shared_ptr<std::vector<rail> const>> m_kept;
|
||||
std::vector<std::reference_wrapper<rail const>> m_rails;
|
||||
};
|
||||
|
||||
// the fastenings of a track with them in the model of its timbers, as laid on the timbers laid with it
|
||||
|
||||
@@ -87,6 +87,12 @@ double constexpr pad_narrowest { 0.02 };
|
||||
double constexpr fastening_overlap { 0.01 };
|
||||
// how far from the camera the fastenings are drawn at most
|
||||
double constexpr fastening_range { 120.0 };
|
||||
// how much further out the fastenings are laid, there as the camera comes near
|
||||
double constexpr fastening_lead { 30.0 };
|
||||
// how near the camera the beams of a track are laid at once as they're needed; further out while the laying in a frame took less
|
||||
// than the budget, in ms, the rest left for the frames after
|
||||
double constexpr lay_near { 50.0 };
|
||||
double constexpr lay_budget { 2.0 };
|
||||
|
||||
// how many tracks a cluster takes at most
|
||||
std::size_t constexpr cluster_cap { 256 };
|
||||
|
||||
@@ -1604,6 +1604,7 @@ void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
track_sleepers::forget_rails( *this );
|
||||
}
|
||||
auto const lay_rail = [&]( int const Path, gfx::vertex_array const &Profile, int const Side, float const Texturelength, double const From, bool const Openstart, bool const Openend, geometryhandle_sequence &Geometry, geometryhandle_sequence &Cuts ) {
|
||||
return this->lay_rail( layout, drawing, Path, Profile, Side, Texturelength, From, Openstart, Openend, Geometry, Cuts ); };
|
||||
|
||||
@@ -123,29 +123,22 @@ std::pair<double, double> shared_zone( TTrack const &Track, int const Path ) {
|
||||
return { zones.front().first, zones.back().second };
|
||||
}
|
||||
|
||||
void lay( TTrack &Track ) {
|
||||
namespace {
|
||||
|
||||
// the beams as instances of the parts of the model of the track: those of the fastenings with them, or left for later and the beams
|
||||
// kept for them meanwhile
|
||||
void instance( TTrack &Track, std::vector<beam> &&Beams, bool const Fastened ) {
|
||||
|
||||
auto &laid { Track.m_sleepers3d };
|
||||
std::vector<beam> placed;
|
||||
if( laid.active && in_background() && timber_model( Track ) != nullptr ) {
|
||||
// worked out in the background; till then the track keeps what it has, and tries again
|
||||
auto beams { laid_out( Track ) };
|
||||
if( false == beams.has_value() ) {
|
||||
ask_layout( Track );
|
||||
return;
|
||||
}
|
||||
placed = std::move( *beams );
|
||||
}
|
||||
laid.dirty = false;
|
||||
for( auto &instances : laid.instances ) {
|
||||
instances.clear();
|
||||
}
|
||||
laid.whole.clear();
|
||||
laid.plain.clear();
|
||||
laid.chunks.clear();
|
||||
laid.timbers = timber_model( Track );
|
||||
laid.plains = plain_model( Track );
|
||||
if( false == laid.active || laid.timbers == nullptr ) {
|
||||
laid.fastened = true;
|
||||
std::vector<beam> {}.swap( laid.beams );
|
||||
if( laid.timbers == nullptr ) {
|
||||
return;
|
||||
}
|
||||
// the sleepers of the model of the track itself (sleepermodel) at the height they're drawn at without the 3D sleepers: the
|
||||
@@ -153,16 +146,6 @@ void lay( TTrack &Track ) {
|
||||
auto const ownplains { laid.plains != nullptr && Track.m_sleeper_enabled && laid.plains != plain_model() };
|
||||
auto const plainlift { ownplains ? Track.rail_height() + Track.m_sleeper_offset.z : 0.f };
|
||||
auto const &parts { *laid.timbers };
|
||||
if( auto const panel { panel_off_plane( Track ) }; panel.first > coplanar_tolerance ) {
|
||||
WriteLog(
|
||||
"sleepers3d: switch \"" + Track.name() + "\" has its paths " + to_string( panel.first * 1000.0, 1 ) + " mm off one plane "
|
||||
+ to_string( panel.second, 2 ) + " m along, where they share the timbers of its panel" );
|
||||
}
|
||||
laid.laying = true;
|
||||
auto const beams { in_background() ? std::move( placed ) : place( Track ) };
|
||||
laid.laying = false;
|
||||
// the layout of the cluster isn't needed by this track any more, the instances below are what's drawn
|
||||
forget_layout( Track );
|
||||
|
||||
// the rails around, where they lie on the timbers, for the fastenings of the model; found at the first timber, none for plain sleepers
|
||||
std::optional<fastened_rails> rails;
|
||||
@@ -199,7 +182,7 @@ void lay( TTrack &Track ) {
|
||||
runbeams.clear();
|
||||
};
|
||||
|
||||
for( auto const &beam : beams ) {
|
||||
for( auto const &beam : Beams ) {
|
||||
if( runbeams.empty() ) {
|
||||
for( int part = 0; part < part_count; ++part ) {
|
||||
run.first[ part ] = static_cast<std::uint32_t>( laid.instances[ part ].size() );
|
||||
@@ -265,7 +248,7 @@ void lay( TTrack &Track ) {
|
||||
put( part_end, scale, parts.spans[ part_end ].x, -half );
|
||||
put( part_begin, scale, parts.spans[ part_begin ].y, half );
|
||||
}
|
||||
if( parts.fastened() && false == ( beam.plain && laid.plains != nullptr ) ) {
|
||||
if( Fastened && parts.fastened() && false == ( beam.plain && laid.plains != nullptr ) ) {
|
||||
if( false == rails.has_value() ) {
|
||||
rails.emplace( Track );
|
||||
}
|
||||
@@ -296,6 +279,55 @@ void lay( TTrack &Track ) {
|
||||
laid.whole.shrink_to_fit();
|
||||
laid.plain.shrink_to_fit();
|
||||
laid.chunks.shrink_to_fit();
|
||||
if( false == Fastened && parts.fastened() ) {
|
||||
laid.fastened = false;
|
||||
laid.beams = std::move( Beams );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void lay( TTrack &Track, bool const Fastened ) {
|
||||
|
||||
auto &laid { Track.m_sleepers3d };
|
||||
std::vector<beam> placed;
|
||||
if( laid.active && in_background() && timber_model( Track ) != nullptr ) {
|
||||
// worked out in the background; till then the track keeps what it has, and tries again
|
||||
auto beams { laid_out( Track ) };
|
||||
if( false == beams.has_value() ) {
|
||||
ask_layout( Track );
|
||||
return;
|
||||
}
|
||||
placed = std::move( *beams );
|
||||
}
|
||||
laid.dirty = false;
|
||||
laid.timbers = timber_model( Track );
|
||||
laid.plains = plain_model( Track );
|
||||
if( false == laid.active || laid.timbers == nullptr ) {
|
||||
instance( Track, {}, true );
|
||||
return;
|
||||
}
|
||||
if( auto const panel { panel_off_plane( Track ) }; panel.first > coplanar_tolerance ) {
|
||||
WriteLog(
|
||||
"sleepers3d: switch \"" + Track.name() + "\" has its paths " + to_string( panel.first * 1000.0, 1 ) + " mm off one plane "
|
||||
+ to_string( panel.second, 2 ) + " m along, where they share the timbers of its panel" );
|
||||
}
|
||||
laid.laying = true;
|
||||
auto beams { in_background() ? std::move( placed ) : place( Track ) };
|
||||
laid.laying = false;
|
||||
// the layout of the cluster isn't needed by this track any more, the instances below are what's drawn
|
||||
forget_layout( Track );
|
||||
instance( Track, std::move( beams ), Fastened );
|
||||
}
|
||||
|
||||
void fasten( TTrack &Track ) {
|
||||
|
||||
auto &laid { Track.m_sleepers3d };
|
||||
if( laid.fastened || laid.dirty ) {
|
||||
return;
|
||||
}
|
||||
auto beams { std::move( laid.beams ) };
|
||||
instance( Track, std::move( beams ), true );
|
||||
}
|
||||
|
||||
void release_far( glm::dvec3 const &Camera, double const Range ) {
|
||||
@@ -309,15 +341,19 @@ void release_far( glm::dvec3 const &Camera, double const Range ) {
|
||||
next = 0;
|
||||
}
|
||||
auto *track { tracks[ next++ ] };
|
||||
if( track == nullptr || false == track->m_sleepers3d.active || track->m_sleepers3d.laying ) {
|
||||
if( track == nullptr || track->m_sleepers3d.laying ) {
|
||||
continue;
|
||||
}
|
||||
if( glm::length( track->location() - Camera ) - track->radius() <= Range ) {
|
||||
continue;
|
||||
}
|
||||
forget_rails( *track );
|
||||
if( false == track->m_sleepers3d.active ) {
|
||||
continue;
|
||||
}
|
||||
auto &laid { track->m_sleepers3d };
|
||||
forget_layout( *track );
|
||||
auto const holds { laid.chunks.capacity() > 0 || laid.whole.capacity() > 0 || laid.plain.capacity() > 0
|
||||
auto const holds { laid.chunks.capacity() > 0 || laid.whole.capacity() > 0 || laid.plain.capacity() > 0 || laid.beams.capacity() > 0
|
||||
|| std::any_of( laid.instances.begin(), laid.instances.end(), []( std::vector<glm::mat4> const &Instances ) { return Instances.capacity() > 0; } ) };
|
||||
if( false == holds ) {
|
||||
continue;
|
||||
@@ -328,6 +364,7 @@ void release_far( glm::dvec3 const &Camera, double const Range ) {
|
||||
std::vector<glm::mat4> {}.swap( laid.whole );
|
||||
std::vector<glm::mat4> {}.swap( laid.plain );
|
||||
std::vector<chunk> {}.swap( laid.chunks );
|
||||
std::vector<beam> {}.swap( laid.beams );
|
||||
laid.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ struct laid {
|
||||
std::vector<glm::mat4> whole; // transforms of the timbers of a model without parts, drawn whole
|
||||
std::vector<glm::mat4> plain; // transforms of the plain sleepers, whole models, relative to the origin of the track
|
||||
std::vector<chunk> chunks;
|
||||
bool fastened { false }; // the fastenings are laid, else they're laid as the track comes near where they're drawn
|
||||
std::vector<beam> beams; // kept for the fastenings till they're laid
|
||||
};
|
||||
|
||||
// how far the ballast of a track with beams is lowered, so they stick out of it
|
||||
@@ -147,10 +149,14 @@ struct pack_model {
|
||||
// the models of sleepers and timbers in the scenery data, found once in models/ by the names of their files telling sleepers
|
||||
// or timbers: podklad, podrozjazd, sleeper, timber. the timber ones first, then by the name
|
||||
std::vector<pack_model> const &pack_models();
|
||||
// the beams of the track placed anew, as instances of the parts of the model
|
||||
void lay( TTrack &Track );
|
||||
// the beams of the track placed anew, as instances of the parts of the model; with the fastenings, or those left for later
|
||||
void lay( TTrack &Track, bool const Fastened = true );
|
||||
// the fastenings left out laid on the beams of the track
|
||||
void fasten( TTrack &Track );
|
||||
// the beams of the tracks around the track to be placed again, as they depend on where it runs
|
||||
void unsettle_around( TTrack &Track );
|
||||
// the rails of the track kept for the fastenings of the tracks around let go, as they're laid anew or the track goes far
|
||||
void forget_rails( TTrack const &Track );
|
||||
// the beams worked out in a thread of their own as the tracks come near, while the simulation runs; off in the editor, where the
|
||||
// tracks change and the beams are worked out as they're needed. turning it off waits for the beams being worked out
|
||||
void lay_in_background( bool const Background );
|
||||
|
||||
Reference in New Issue
Block a user