mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 06:19:19 +02:00
refactor(track): reusable segment init, geometry rebuild, cell removal
This commit is contained in:
@@ -300,8 +300,8 @@ geometry_bank::replace( gfx::vertex_array &Vertices, userdata_array &Userdata, g
|
||||
// TBD: we could bail out with an error instead if such request occurs
|
||||
chunk.vertices.resize( Offset + Vertices.size(), gfx::basic_vertex() );
|
||||
chunk.userdata.resize( Offset + Userdata.size(), gfx::vertex_userdata() );
|
||||
chunk.vertices.insert( std::end( chunk.vertices ), std::begin( Vertices ), std::end( Vertices ) );
|
||||
chunk.userdata.insert( std::end( chunk.userdata ), std::begin( Userdata ), std::end( Userdata ) );
|
||||
std::copy( std::begin( Vertices ), std::end( Vertices ), std::begin( chunk.vertices ) + Offset );
|
||||
std::copy( std::begin( Userdata ), std::end( Userdata ), std::begin( chunk.userdata ) + Offset );
|
||||
}
|
||||
// template method implementation
|
||||
replace_( Geometry );
|
||||
|
||||
@@ -416,6 +416,40 @@ basic_cell::insert( TMemCell *Memorycell ) {
|
||||
// NOTE: memory cells are virtual 'points' hence they don't ever expand cell range
|
||||
}
|
||||
|
||||
// removes provided path from the cell
|
||||
void
|
||||
basic_cell::erase( TTrack *Path ) {
|
||||
|
||||
m_paths.erase(
|
||||
std::remove( std::begin( m_paths ), std::end( m_paths ), Path ),
|
||||
std::end( m_paths ) );
|
||||
// drop the path from the animation list, the cell won't update it anymore
|
||||
if( tTrackAnim == Path ) {
|
||||
tTrackAnim = Path->SwitchExtension->pNextAnim;
|
||||
Path->SwitchExtension->pNextAnim = nullptr;
|
||||
}
|
||||
else {
|
||||
for( auto *track = tTrackAnim; track != nullptr; track = track->SwitchExtension->pNextAnim ) {
|
||||
if( track->SwitchExtension->pNextAnim == Path ) {
|
||||
track->SwitchExtension->pNextAnim = Path->SwitchExtension->pNextAnim;
|
||||
Path->SwitchExtension->pNextAnim = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Path->RaOwnerSet( nullptr );
|
||||
// TODO: update cell bounding area
|
||||
}
|
||||
|
||||
// removes provided path from the lookup directory of the cell
|
||||
void
|
||||
basic_cell::unregister_end( TTrack *Path ) {
|
||||
|
||||
m_directories.paths.erase(
|
||||
std::remove( std::begin( m_directories.paths ), std::end( m_directories.paths ), Path ),
|
||||
std::end( m_directories.paths ) );
|
||||
}
|
||||
|
||||
// removes provided model instance from the cell
|
||||
void
|
||||
basic_cell::erase( TAnimModel *Instance ) {
|
||||
|
||||
@@ -145,6 +145,12 @@ public:
|
||||
// registers provided traction piece in the lookup directory of the cell
|
||||
void
|
||||
register_end( TTraction *Traction );
|
||||
// removes provided path from the cell
|
||||
void
|
||||
erase( TTrack *Path );
|
||||
// removes provided path from the lookup directory of the cell
|
||||
void
|
||||
unregister_end( TTrack *Path );
|
||||
// removes provided model instance from the cell
|
||||
void
|
||||
erase( TAnimModel *Instance );
|
||||
@@ -308,6 +314,11 @@ public:
|
||||
void
|
||||
register_node( Type_ *Node, glm::dvec3 const &Point ) {
|
||||
cell( Point ).register_end( Node ); }
|
||||
// removes provided node from the lookup directory of the section enclosing specified point
|
||||
template <class Type_>
|
||||
void
|
||||
unregister_node( Type_ *Node, glm::dvec3 const &Point ) {
|
||||
cell( Point ).unregister_end( Node ); }
|
||||
// find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );
|
||||
@@ -435,6 +446,14 @@ public:
|
||||
auto const location{ Node->location() };
|
||||
if( point_inside( location ) ) {
|
||||
section( location ).erase( Node ); } }
|
||||
// removes specified node from the region and from the lookup directories of its ends
|
||||
template <class Type_>
|
||||
void
|
||||
erase_and_unregister( Type_ *Node ) {
|
||||
for( auto const &point : Node->endpoints() ) {
|
||||
if( point_inside( point ) ) {
|
||||
section( point ).unregister_node( Node, point ); } }
|
||||
erase( Node ); }
|
||||
// find a vehicle located nearest to specified point, within specified radius. reurns: located vehicle and distance
|
||||
std::tuple<TDynamicObject *, float>
|
||||
find_vehicle( glm::dvec3 const &Point, float const Radius, bool const Onlycontrolled, bool const Findbycoupler );
|
||||
|
||||
397
world/Track.cpp
397
world/Track.cpp
@@ -382,8 +382,7 @@ void TTrack::ConnectNextNext(TTrack *pTrack, int typ)
|
||||
|
||||
void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
{ // pobranie obiektu trajektorii ruchu
|
||||
glm::dvec3 pt, vec, p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
|
||||
double a1, a2, r1, r2, r3, r4;
|
||||
double a1, a2;
|
||||
std::string str;
|
||||
size_t i; //,state; //Ra: teraz już nie ma początkowego stanu zwrotnicy we wpisie
|
||||
std::string token;
|
||||
@@ -501,8 +500,6 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
else if (Global.iWriteLogEnabled & 4)
|
||||
WriteLog("unvis");
|
||||
Init(); // ustawia SwitchExtension
|
||||
double segsize = 5.0; // długość odcinka segmentowania
|
||||
|
||||
// path data
|
||||
// all subtypes contain at least one path
|
||||
m_paths.emplace_back();
|
||||
@@ -521,6 +518,198 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
init_segments( true );
|
||||
|
||||
// optional attributes
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
while (str != "endtrack")
|
||||
{
|
||||
if (str == "event0")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events0.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events1.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events2.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall0")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events0all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events1all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> 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::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
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
Isolated.push_back(TIsolated::Find(token));
|
||||
}
|
||||
else if (str == "angle1")
|
||||
{ // kąt ścięcia końca od strony 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a1;
|
||||
//Segment->AngleSet(0, a1);
|
||||
}
|
||||
else if (str == "angle2")
|
||||
{ // kąt ścięcia końca od strony 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a2;
|
||||
//Segment->AngleSet(1, a2);
|
||||
}
|
||||
else if (str == "fouling1")
|
||||
{ // wskazanie modelu ukresu w kierunku 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[0]=
|
||||
}
|
||||
else if (str == "fouling2")
|
||||
{ // wskazanie modelu ukresu w kierunku 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[1]=
|
||||
}
|
||||
else if (str == "overhead")
|
||||
{ // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości
|
||||
parser->getTokens();
|
||||
*parser >> fOverhead;
|
||||
if (fOverhead > 0.0)
|
||||
iAction |= 0x40; // flaga opuszczenia pantografu (tor uwzględniany w skanowaniu jako
|
||||
// ograniczenie dla pantografujących)
|
||||
}
|
||||
else if( str == "vradius" ) {
|
||||
// y-axis track radius
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> fVerticalRadius;
|
||||
}
|
||||
else if( str == "trackbed" ) {
|
||||
// switch trackbed texture
|
||||
auto const trackbedtexture { parser->getToken<std::string>() };
|
||||
if( eType == tt_Switch ) {
|
||||
SwitchExtension->m_material3 = GfxRenderer->Fetch_Material( trackbedtexture );
|
||||
}
|
||||
}
|
||||
else if( str == "railprofile" ) {
|
||||
// rail profile
|
||||
auto const railprofile { parser->getToken<std::string>() };
|
||||
if( iCategoryFlag == 1 ) {
|
||||
m_profile1 = fetch_track_rail_profile( railprofile );
|
||||
}
|
||||
}
|
||||
else if( str == "friction" ) {
|
||||
// memory cell holding friction value modifiers
|
||||
m_friction.first = parser->getToken<std::string>();
|
||||
}
|
||||
else if( str == "sleepermodel" ) {
|
||||
// sleepermodel <frequency> <model> <skin> <offsetX> <offsetY> <offsetZ> <ballastZ>
|
||||
// - frequency: meters between consecutive sleeper instances (must be > 0)
|
||||
// - model: path to the .e3d sleeper model
|
||||
// - skin: replacable skin path, or "none" for the model's defaults
|
||||
// - offset: local-space offset applied per-instance (x=left/right, y=forward/back, z=up/down)
|
||||
// - ballastZ: vertical shift applied to the auto-generated trackbed (ballast). negative pushes ballast down.
|
||||
float frequency { 0.f };
|
||||
float offsetx { 0.f }, offsety { 0.f }, offsetz { 0.f };
|
||||
float ballastz { 0.f };
|
||||
parser->getTokens( 1, false ); *parser >> frequency;
|
||||
auto modelpath { parser->getToken<std::string>( false ) };
|
||||
auto skinpath { parser->getToken<std::string>( false ) };
|
||||
parser->getTokens( 3, false ); *parser >> offsetx >> offsety >> offsetz;
|
||||
parser->getTokens( 1, false ); *parser >> ballastz;
|
||||
|
||||
if( frequency <= 0.01f ) {
|
||||
ErrorLog( "Bad track: invalid sleepermodel frequency (" + std::to_string( frequency ) + ") for track \"" + m_name + "\"" );
|
||||
}
|
||||
else {
|
||||
replace_slashes( modelpath );
|
||||
m_sleeper_enabled = true;
|
||||
m_sleeper_frequency = frequency;
|
||||
m_sleeper_model_name = modelpath;
|
||||
m_sleeper_skin_name = skinpath;
|
||||
m_sleeper_offset = glm::vec3( offsetx, offsety, offsetz );
|
||||
m_sleeper_ballast_z = ballastz;
|
||||
// model and skin are resolved (and instance transforms baked) in build_sleeper_transforms,
|
||||
// called after segment initialisation so the path geometry is final.
|
||||
}
|
||||
}
|
||||
else
|
||||
ErrorLog("Bad track: unknown property: \"" + str + "\" defined for track \"" + m_name + "\"");
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
}
|
||||
// alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru
|
||||
if ((i = m_name.find("@")) != std::string::npos && i < m_name.length())
|
||||
{
|
||||
Isolated.push_back(TIsolated::Find(m_name.substr(i + 1, m_name.length())));
|
||||
m_name = m_name.substr(0, i - 1); // usunięcie z nazwy
|
||||
}
|
||||
|
||||
update_location();
|
||||
// sleeper transforms are baked later in create_geometry(), once the owning cell has
|
||||
// assigned this track its m_origin (otherwise the local-space matrices would be relative
|
||||
// to a stale origin and the renderer would draw sleepers in the wrong place).
|
||||
}
|
||||
|
||||
// calculates path location from the current segment
|
||||
void TTrack::update_location() {
|
||||
|
||||
location( (
|
||||
CurrentSegment()->FastGetPoint_0()
|
||||
+ CurrentSegment()->FastGetPoint( 0.5 )
|
||||
+ CurrentSegment()->FastGetPoint_1() )
|
||||
/ 3.0 );
|
||||
}
|
||||
|
||||
// (re)creates path segments from the source path data in m_paths
|
||||
// Initial: true when called during deserialization; the editor passes false to keep the current switch state
|
||||
void TTrack::init_segments( bool const Initial ) {
|
||||
|
||||
glm::dvec3 p1, p2, cp1, cp2, p3, p4, cp3, cp4; // dodatkowe punkty potrzebne do skrzyżowań
|
||||
double r1, r2, r3, r4;
|
||||
double segsize = 5.0; // długość odcinka segmentowania
|
||||
|
||||
// TSegment::Init() raises the trackbed for the roll fix through MovedUp1(); drop the previous adjustment
|
||||
// so repeated initialization doesn't accumulate it
|
||||
fTexHeight1 -= fTexHeightOffset;
|
||||
fTexHeightOffset = 0.f;
|
||||
|
||||
switch (eType) {
|
||||
// Ra: łuki segmentowane co 5m albo 314-kątem foremnym
|
||||
case tt_Table: {
|
||||
@@ -773,7 +962,9 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
Switch(0); // na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie
|
||||
if( Initial ) {
|
||||
Switch(0);
|
||||
} // na stałe w położeniu 0 - nie ma początkowego stanu zwrotnicy we wpisie
|
||||
|
||||
if( eType == tt_Switch )
|
||||
// Ra: zamienić później na iloczyn wektorowy
|
||||
@@ -796,177 +987,6 @@ void TTrack::Load(cParser *parser, glm::dvec3 const &pOrigin)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// optional attributes
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
while (str != "endtrack")
|
||||
{
|
||||
if (str == "event0")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events0.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events1.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "event2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events2.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall0")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events0all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall1")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
m_events1all.emplace_back( token, nullptr );
|
||||
}
|
||||
else if (str == "eventall2")
|
||||
{
|
||||
parser->getTokens();
|
||||
*parser >> 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::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
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
Isolated.push_back(TIsolated::Find(token));
|
||||
}
|
||||
else if (str == "angle1")
|
||||
{ // kąt ścięcia końca od strony 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a1;
|
||||
//Segment->AngleSet(0, a1);
|
||||
}
|
||||
else if (str == "angle2")
|
||||
{ // kąt ścięcia końca od strony 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> a2;
|
||||
//Segment->AngleSet(1, a2);
|
||||
}
|
||||
else if (str == "fouling1")
|
||||
{ // wskazanie modelu ukresu w kierunku 1
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[0]=
|
||||
}
|
||||
else if (str == "fouling2")
|
||||
{ // wskazanie modelu ukresu w kierunku 2
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
// nFouling[1]=
|
||||
}
|
||||
else if (str == "overhead")
|
||||
{ // informacja o stanie sieci: 0-jazda bezprądowa, >0-z opuszczonym i ograniczeniem prędkości
|
||||
parser->getTokens();
|
||||
*parser >> fOverhead;
|
||||
if (fOverhead > 0.0)
|
||||
iAction |= 0x40; // flaga opuszczenia pantografu (tor uwzględniany w skanowaniu jako
|
||||
// ograniczenie dla pantografujących)
|
||||
}
|
||||
else if( str == "vradius" ) {
|
||||
// y-axis track radius
|
||||
// NOTE: not used/implemented
|
||||
parser->getTokens();
|
||||
*parser >> fVerticalRadius;
|
||||
}
|
||||
else if( str == "trackbed" ) {
|
||||
// switch trackbed texture
|
||||
auto const trackbedtexture { parser->getToken<std::string>() };
|
||||
if( eType == tt_Switch ) {
|
||||
SwitchExtension->m_material3 = GfxRenderer->Fetch_Material( trackbedtexture );
|
||||
}
|
||||
}
|
||||
else if( str == "railprofile" ) {
|
||||
// rail profile
|
||||
auto const railprofile { parser->getToken<std::string>() };
|
||||
if( iCategoryFlag == 1 ) {
|
||||
m_profile1 = fetch_track_rail_profile( railprofile );
|
||||
}
|
||||
}
|
||||
else if( str == "friction" ) {
|
||||
// memory cell holding friction value modifiers
|
||||
m_friction.first = parser->getToken<std::string>();
|
||||
}
|
||||
else if( str == "sleepermodel" ) {
|
||||
// sleepermodel <frequency> <model> <skin> <offsetX> <offsetY> <offsetZ> <ballastZ>
|
||||
// - frequency: meters between consecutive sleeper instances (must be > 0)
|
||||
// - model: path to the .e3d sleeper model
|
||||
// - skin: replacable skin path, or "none" for the model's defaults
|
||||
// - offset: local-space offset applied per-instance (x=left/right, y=forward/back, z=up/down)
|
||||
// - ballastZ: vertical shift applied to the auto-generated trackbed (ballast). negative pushes ballast down.
|
||||
float frequency { 0.f };
|
||||
float offsetx { 0.f }, offsety { 0.f }, offsetz { 0.f };
|
||||
float ballastz { 0.f };
|
||||
parser->getTokens( 1, false ); *parser >> frequency;
|
||||
auto modelpath { parser->getToken<std::string>( false ) };
|
||||
auto skinpath { parser->getToken<std::string>( false ) };
|
||||
parser->getTokens( 3, false ); *parser >> offsetx >> offsety >> offsetz;
|
||||
parser->getTokens( 1, false ); *parser >> ballastz;
|
||||
|
||||
if( frequency <= 0.01f ) {
|
||||
ErrorLog( "Bad track: invalid sleepermodel frequency (" + std::to_string( frequency ) + ") for track \"" + m_name + "\"" );
|
||||
}
|
||||
else {
|
||||
replace_slashes( modelpath );
|
||||
m_sleeper_enabled = true;
|
||||
m_sleeper_frequency = frequency;
|
||||
m_sleeper_model_name = modelpath;
|
||||
m_sleeper_skin_name = skinpath;
|
||||
m_sleeper_offset = glm::vec3( offsetx, offsety, offsetz );
|
||||
m_sleeper_ballast_z = ballastz;
|
||||
// model and skin are resolved (and instance transforms baked) in build_sleeper_transforms,
|
||||
// called after segment initialisation so the path geometry is final.
|
||||
}
|
||||
}
|
||||
else
|
||||
ErrorLog("Bad track: unknown property: \"" + str + "\" defined for track \"" + m_name + "\"");
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
str = token;
|
||||
}
|
||||
// alternatywny zapis nazwy odcinka izolowanego - po znaku "@" w nazwie toru
|
||||
if ((i = m_name.find("@")) != std::string::npos && i < m_name.length())
|
||||
{
|
||||
Isolated.push_back(TIsolated::Find(m_name.substr(i + 1, m_name.length())));
|
||||
m_name = m_name.substr(0, i - 1); // usunięcie z nazwy
|
||||
}
|
||||
|
||||
// calculate path location
|
||||
location( (
|
||||
CurrentSegment()->FastGetPoint_0()
|
||||
+ CurrentSegment()->FastGetPoint( 0.5 )
|
||||
+ CurrentSegment()->FastGetPoint_1() )
|
||||
/ 3.0 );
|
||||
// sleeper transforms are baked later in create_geometry(), once the owning cell has
|
||||
// assigned this track its m_origin (otherwise the local-space matrices would be relative
|
||||
// to a stale origin and the renderer would draw sleepers in the wrong place).
|
||||
}
|
||||
|
||||
bool TTrack::AssignEvents() {
|
||||
@@ -1333,6 +1353,22 @@ glm::vec3 TTrack::get_nearest_point(const glm::dvec3 &point) const
|
||||
}
|
||||
|
||||
// wypełnianie tablic VBO
|
||||
// discards references to current render geometry and generates it anew in specified bank
|
||||
// NOTE: geometry banks can't release chunks, so the old data stays in the bank, unused
|
||||
void TTrack::rebuild_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
|
||||
if( Bank == null_handle ) { return; }
|
||||
|
||||
Geometry1.clear();
|
||||
Geometry2.clear();
|
||||
if( SwitchExtension ) {
|
||||
SwitchExtension->Geometry3 = gfx::geometry_handle{};
|
||||
}
|
||||
m_sleeper_local_transforms.clear();
|
||||
|
||||
create_geometry( Bank );
|
||||
}
|
||||
|
||||
void TTrack::create_geometry( gfx::geometrybank_handle const &Bank ) {
|
||||
gfx::userdata_array empty_userdata;
|
||||
// bake per-instance sleeper transforms now that the owning cell has assigned m_origin.
|
||||
@@ -2319,6 +2355,8 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
<< fTexSlope << ' ';
|
||||
}
|
||||
// path data
|
||||
// NOTE: default stream precision would round coordinates to centimetres or worse, breaking path connections
|
||||
auto const precision { Output.precision( std::numeric_limits<double>::digits10 ) };
|
||||
for( auto const &path : m_paths ) {
|
||||
Output
|
||||
<< path.points[ segment_data::point::start ].x << ' '
|
||||
@@ -2341,6 +2379,7 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
|
||||
<< path.radius << ' ';
|
||||
}
|
||||
Output.precision( precision );
|
||||
// optional attributes
|
||||
std::vector< std::pair< std::string, event_sequence const * > > const eventsequences {
|
||||
{ "event0", &m_events0 }, { "eventall0", &m_events0all },
|
||||
@@ -2379,13 +2418,17 @@ TTrack::export_as_text_( std::ostream &Output ) const {
|
||||
}
|
||||
if( eType == tt_Switch
|
||||
&& SwitchExtension->m_material3 != null_handle) {
|
||||
auto texturefile { GfxRenderer->Material( m_material2 )->GetName() };
|
||||
auto texturefile { GfxRenderer->Material( SwitchExtension->m_material3 )->GetName() };
|
||||
if( texturefile.find( paths::textures ) == 0 ) {
|
||||
// don't include 'textures/' in the path
|
||||
texturefile.erase( 0, std::string{ paths::textures }.size() );
|
||||
}
|
||||
Output << "trackbed " << texturefile << ' ';
|
||||
}
|
||||
if( iCategoryFlag == 1
|
||||
&& false == m_profile1.first.empty() ) {
|
||||
Output << "railprofile " << m_profile1.first << ' ';
|
||||
}
|
||||
if( false == m_friction.first.empty() ) {
|
||||
Output << "friction " << m_friction.first << ' ';
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ class TTrack : public scene::basic_node
|
||||
friend opengl33_renderer;
|
||||
// NOTE: temporary arrangement
|
||||
friend itemproperties_panel;
|
||||
friend class editor_track;
|
||||
|
||||
public:
|
||||
std::vector<TIsolated*> Isolated; // obwód izolowany obsługujący zajęcia/zwolnienia grupy torów
|
||||
@@ -278,6 +279,10 @@ public:
|
||||
RouteCount() const {
|
||||
return SwitchExtension != nullptr ? SwitchExtension->iRoads - 1 : 1; }
|
||||
void Load(cParser *parser, glm::dvec3 const &pOrigin);
|
||||
// (re)creates path segments from the source path data in m_paths
|
||||
void init_segments( bool const Initial );
|
||||
// calculates path location from the current segment
|
||||
void update_location();
|
||||
bool AssignEvents();
|
||||
bool AssignForcedEvents(basic_event *NewEventPlus, basic_event *NewEventMinus);
|
||||
void QueueEvents( event_sequence const &Events, TDynamicObject const *Owner );
|
||||
@@ -300,6 +305,8 @@ public:
|
||||
double ActiveLength();
|
||||
|
||||
void create_geometry( gfx::geometrybank_handle const &Bank ); // wypełnianie VBO
|
||||
// discards current render geometry and generates it anew in specified bank
|
||||
void rebuild_geometry( gfx::geometrybank_handle const &Bank );
|
||||
void create_map_geometry(std::vector<gfx::basic_vertex> &Bank, const gfx::geometrybank_handle Extra);
|
||||
void get_map_active_paths(map_colored_paths &handles);
|
||||
void get_map_paths_for_state(map_colored_paths &handles, int state);
|
||||
|
||||
Reference in New Issue
Block a user