build 171027: bounding area calculation fixes, novice ui obstacle indicator, minor traction render enhancement, shadow calculations for tall enough platforms

This commit is contained in:
tmj-fstate
2017-10-28 00:56:10 +02:00
parent d8c3b5caf4
commit 4ce975a656
23 changed files with 334 additions and 138 deletions

View File

@@ -583,6 +583,15 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
m_framestamp = Framestamp;
};
// calculates piece's bounding radius
void
TAnimModel::radius_() {
if( pModel != nullptr ) {
m_area.radius = pModel->bounding_radius();
}
}
void TAnimModel::RaPrepare()
{ // ustawia światła i animacje we wzorcu modelu przed renderowaniem egzemplarza
bool state; // stan światła

View File

@@ -157,6 +157,11 @@ public:
// members
static TAnimContainer *acAnimList; // lista animacji z eventem, które muszą być przeliczane również bez wyświetlania
protected:
// calculates piece's bounding radius
void
radius_();
private:
// methods
void RaPrepare(); // ustawienie animacji egzemplarza na wzorcu

View File

@@ -121,7 +121,7 @@ bool TEventLauncher::Load(cParser *parser)
*parser >> token;
}
return true;
};
}
bool TEventLauncher::check_conditions()
{ //"renderowanie" wyzwalacza
@@ -184,6 +184,13 @@ bool TEventLauncher::IsGlobal() const {
&& ( iHour >= 0 )
&& ( iMinute >= 0 )
&& ( dRadius < 0.0 ) ); // bez ograniczenia zasięgu
};
}
// calculates node's bounding radius
void
TEventLauncher::radius_() {
m_area.radius = std::sqrt( dRadius );
}
//---------------------------------------------------------------------------

View File

@@ -37,6 +37,11 @@ public:
int iCheckMask { 0 };
double dRadius { 0.0 };
protected:
// calculates node's bounding radius
void
radius_();
private:
// members
int iKey { 0 };

View File

@@ -1562,6 +1562,9 @@ TGroundNode * TGround::AddGroundNode(cParser *parser)
break;
}
#endif
default: {
break;
}
}
return tmp;
}

View File

@@ -29,8 +29,8 @@ http://mozilla.org/MPL/2.0/.
TMemCell::TMemCell(vector3 *p)
{
fValue1 = fValue2 = 0;
m_location =
p ? *p : glm::dvec3(); // ustawienie współrzędnych, bo do TGroundNode nie ma dostępu
location(
p ? *p : glm::dvec3() ); // ustawienie współrzędnych, bo do TGroundNode nie ma dostępu
bCommand = false; // komenda wysłana
OnSent = NULL;
}
@@ -110,9 +110,9 @@ bool TMemCell::Load(cParser *parser)
#else
parser->getTokens( 6, false );
*parser
>> m_location.x
>> m_location.y
>> m_location.z
>> m_area.center.x
>> m_area.center.y
>> m_area.center.z
#endif
>> szText
>> fValue1

View File

@@ -16,16 +16,7 @@ http://mozilla.org/MPL/2.0/.
class TMemCell : public editor::basic_node {
private:
// content
std::string szText;
double fValue1 { 0.0 };
double fValue2 { 0.0 };
// other
TCommandType eCommand { cm_Unknown };
bool bCommand { false }; // czy zawiera komendę dla zatrzymanego AI
TEvent *OnSent { nullptr }; // event dodawany do kolejki po wysłaniu komendy zatrzymującej skład
public:
public:
std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac
TMemCell( scene::node_data const &Nodedata );
@@ -63,6 +54,16 @@ class TMemCell : public editor::basic_node {
TCommandType CommandCheck();
bool IsVelocity();
void AssignEvents(TEvent *e);
private:
// content
std::string szText;
double fValue1 { 0.0 };
double fValue2 { 0.0 };
// other
TCommandType eCommand { cm_Unknown };
bool bCommand { false }; // czy zawiera komendę dla zatrzymanego AI
TEvent *OnSent { nullptr }; // event dodawany do kolejki po wysłaniu komendy zatrzymującej skład
};

View File

@@ -1008,7 +1008,10 @@ TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &
if( m_geometry != NULL ) {
// calculate bounding radius while we're at it
// NOTE: doesn't take into account transformation hierarchy TODO: implement it
float squaredradius{ 0.f };
float squaredradius { 0.f };
// if this happens to be root node it may already have non-squared radius of the largest child
// since we're comparing squared radii, we need to square it back for correct results
m_boundingradius *= m_boundingradius;
for( auto const &vertex : GfxRenderer.Vertices( m_geometry ) ) {
squaredradius = static_cast<float>( glm::length2( vertex.position ) );
if( squaredradius > m_boundingradius ) {
@@ -1016,12 +1019,15 @@ TSubModel::create_geometry( std::size_t &Dataoffset, geometrybank_handle const &
}
}
if( m_boundingradius > 0.f ) { m_boundingradius = std::sqrt( m_boundingradius ); }
if( Parent ) {
// propagate radius up the chain
Parent->m_boundingradius = std::max(
Parent->m_boundingradius,
m_boundingradius );
// adjust overall radius if needed
// NOTE: the method to access root submodel is... less than ideal
auto *root { this };
while( root->Parent != nullptr ) {
root = root->Parent;
}
root->m_boundingradius = std::max(
root->m_boundingradius,
m_boundingradius );
}
if( Next )

View File

@@ -867,11 +867,11 @@ void TTrack::Load(cParser *parser, vector3 pOrigin)
}
// calculate path location
m_location = glm::dvec3{ (
m_area.center = ( glm::dvec3{ (
CurrentSegment()->FastGetPoint_0()
+ CurrentSegment()->FastGetPoint( 0.5 )
+ CurrentSegment()->FastGetPoint_1() )
/ 3.0 };
/ 3.0 } );
}
// TODO: refactor this mess
@@ -2821,6 +2821,18 @@ TTrack::endpoints() const {
}
}
// calculates path's bounding radius
void
TTrack::radius_() {
auto const points = endpoints();
for( auto &point : points ) {
m_area.radius = std::max(
m_area.radius,
static_cast<float>( glm::length( m_area.center - point ) ) ); // extra margin to prevent driven vehicle from flicking
}
}
void TTrack::MovedUp1(float const dh)
{ // poprawienie przechyłki wymaga wydłużenia podsypki
fTexHeight1 += dh;

11
Track.h
View File

@@ -182,9 +182,9 @@ public:
TEnvironmentType eEnvironment = e_flat; // dźwięk i oświetlenie
int iAction = 0; // czy modyfikowany eventami (specjalna obsługa przy skanowaniu)
float fOverhead = -1.0; // można normalnie pobierać prąd (0 dla jazdy bezprądowej po danym odcinku, >0-z opuszczonym i ograniczeniem prędkości)
private:
private:
double fVelocity = -1.0; // ograniczenie prędkości // prędkość dla AI (powyżej rośnie prawdopowobieństwo wykolejenia)
public:
public:
// McZapkie-100502:
double fTrackLength = 100.0; // długość z wpisu, nigdzie nie używana
double fRadius = 0.0; // promień, dla zwrotnicy kopiowany z tabeli
@@ -287,7 +287,12 @@ public:
double VelocityGet();
void ConnectionsLog();
private:
protected:
// calculates path's bounding radius
void
radius_();
private:
void EnvironmentSet();
void EnvironmentReset();
};

View File

@@ -169,7 +169,7 @@ TTraction::Load( cParser *parser, glm::dvec3 const &pOrigin ) {
Init(); // przeliczenie parametrów
// calculate traction location
m_location = interpolate( pPoint2, pPoint1, 0.5 );
location( interpolate( pPoint2, pPoint1, 0.5 ) );
}
// retrieves list of the track's end points
@@ -543,6 +543,18 @@ double TTraction::VoltageGet(double u, double i)
return 0.0; // gdy nie podłączony wcale?
};
// calculates path's bounding radius
void
TTraction::radius_() {
auto const points = endpoints();
for( auto &point : points ) {
m_area.radius = std::max(
m_area.radius,
static_cast<float>( glm::length( m_area.center - point ) ) );
}
}
glm::vec3
TTraction::wire_color() const {

View File

@@ -64,7 +64,6 @@ class TTraction : public editor::basic_node {
// retrieves list of the track's end points
std::vector<glm::dvec3>
endpoints() const;
// creates geometry data in specified geometry bank. returns: number of created elements, or NULL
// NOTE: deleting nodes doesn't currently release geometry data owned by the node. TODO: implement erasing individual geometry chunks and banks
#ifdef EU07_USE_OLD_GROUNDCODE
@@ -79,6 +78,12 @@ class TTraction : public editor::basic_node {
void ResistanceCalc(int d = -1, double r = 0, TTractionPowerSource *ps = nullptr);
void PowerSet(TTractionPowerSource *ps);
double VoltageGet(double u, double i);
protected:
// calculates piece's bounding radius
void
radius_();
private:
glm::vec3 wire_color() const;
};

View File

@@ -42,9 +42,9 @@ bool TTractionPowerSource::Load(cParser *parser) {
#else
parser->getTokens( 10, false );
*parser
>> m_location.x
>> m_location.y
>> m_location.z
>> m_area.center.x
>> m_area.center.y
>> m_area.center.z
#endif
>> NominalVoltage
>> VoltageFrequency

View File

@@ -7029,7 +7029,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
/*
TGauge *gg { nullptr }; // roboczy wskaźnik na obiekt animujący gałkę
*/
std::unordered_map<std::string, TGauge &> gauges = {
std::unordered_map<std::string, TGauge &> const gauges = {
{ "mainctrl:", ggMainCtrl },
{ "scndctrl:", ggScndCtrl },
{ "dirkey:" , ggDirKey },

View File

@@ -1352,7 +1352,8 @@ TWorld::Update_UI() {
uitextline1 += " (paused)";
}
if( Controlled && ( Controlled->Mechanik != nullptr ) ) {
if( ( Controlled != nullptr )
&& ( Controlled->Mechanik != nullptr ) ) {
auto const &mover = Controlled->MoverParameters;
auto const &driver = Controlled->Mechanik;
@@ -1374,6 +1375,11 @@ TWorld::Update_UI() {
uitextline3 +=
" Pressure: " + to_string( mover->BrakePress * 100.0, 2 ) + " kPa"
+ " (train pipe: " + to_string( mover->PipePress * 100.0, 2 ) + " kPa)";
auto const trackblockdistance{ std::abs( Controlled->Mechanik->TrackBlock() ) };
if( trackblockdistance <= 75.0 ) {
uitextline4 = " Another vehicle ahead (distance: " + to_string( trackblockdistance, 1 ) + " m)";
}
}
}

View File

@@ -420,7 +420,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glColor4f( 1.f, 0.9f, 0.8f, 1.f );
::glDisable( GL_LIGHTING );
::glDisable( GL_TEXTURE_2D );
if( true == Global::RenderShadows ) {
if( ( true == Global::RenderShadows ) && ( false == Global::bWireFrame ) ) {
shadowcamera.draw( m_renderpass.camera.position() - shadowcamera.position() );
}
if( DebugCameraFlag ) {
@@ -2214,11 +2214,11 @@ opengl_renderer::Render( TAnimModel *Instance ) {
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = SquareMagnitude( ( Instance->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Instance->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
default: {
distancesquared = SquareMagnitude( ( Instance->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
}
@@ -2246,7 +2246,7 @@ opengl_renderer::Render( TAnimModel *Instance ) {
Instance->pModel,
Instance->Material(),
distancesquared,
Instance->m_location - m_renderpass.camera.position(),
Instance->location() - m_renderpass.camera.position(),
Instance->vAngle );
}
}
@@ -2799,6 +2799,17 @@ void
opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First, scene::basic_cell::path_sequence::const_iterator Last ) {
::glColor3fv( glm::value_ptr( colors::white ) );
// setup
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// NOTE: roads-based platforms tend to miss parts of shadows if rendered with either back or front culling
::glDisable( GL_CULL_FACE );
break;
}
default: {
break;
}
}
// first pass, material 1
for( auto first { First }; first != Last; ++first ) {
@@ -2824,7 +2835,16 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
track->EnvironmentReset();
break;
}
case rendermode::shadows: // shadows are calculated only for trackbeds
case rendermode::shadows: {
if( ( std::abs( track->fTexHeight1 ) < 0.35f )
|| ( track->iCategoryFlag != 2 ) ) {
// shadows are only calculated for high enough roads, typically meaning track platforms
continue;
}
Bind_Material( track->m_material1 );
m_geometry.draw( std::begin( track->Geometry1 ), std::end( track->Geometry1 ) );
break;
}
case rendermode::pickscenery: // pick scenery mode uses piece-by-piece approach
case rendermode::pickcontrols:
default: {
@@ -2854,9 +2874,10 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
break;
}
case rendermode::shadows: {
if( ( track->iCategoryFlag != 1 )
|| ( track->eType != tt_Normal ) ) {
// shadows are only calculated for trackbeds
if( ( std::abs( track->fTexHeight1 ) < 0.35f )
|| ( ( track->iCategoryFlag == 1 )
&& ( track->eType != tt_Normal ) ) ) {
// shadows are only calculated for high enough trackbeds
continue;
}
Bind_Material( track->m_material2 );
@@ -2870,6 +2891,16 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
}
}
}
// post-render reset
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
::glEnable( GL_CULL_FACE );
break;
}
default: {
break;
}
}
}
void
@@ -3218,11 +3249,11 @@ opengl_renderer::Render_Alpha( TAnimModel *Instance ) {
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = SquareMagnitude( ( Instance->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Instance->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
default: {
distancesquared = SquareMagnitude( ( Instance->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
}
@@ -3238,7 +3269,7 @@ opengl_renderer::Render_Alpha( TAnimModel *Instance ) {
Instance->pModel,
Instance->Material(),
distancesquared,
Instance->m_location - m_renderpass.camera.position(),
Instance->location() - m_renderpass.camera.position(),
Instance->vAngle );
}
}
@@ -3250,11 +3281,11 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
switch( m_renderpass.draw_mode ) {
case rendermode::shadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = SquareMagnitude( ( Traction->m_location - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Traction->location() - Global::pCameraPosition ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
default: {
distancesquared = SquareMagnitude( ( Traction->m_location - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
distancesquared = SquareMagnitude( ( Traction->location() - m_renderpass.camera.position() ) / Global::ZoomFactor ) / Global::fDistanceFactor;
break;
}
}
@@ -3272,15 +3303,29 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
return;
}
// setup
/*
float const linealpha = static_cast<float>(
std::min(
1.25,
5000 * Traction->WireThickness / ( distancesquared + 1.0 ) ) ); // zbyt grube nie są dobre
::glLineWidth( linealpha );
*/
auto const distance { static_cast<float>( std::sqrt( distancesquared ) ) };
auto const linealpha {
20.f * Traction->WireThickness
/ std::max(
0.5f * Traction->radius() + 1.f,
distance - ( 0.5f * Traction->radius() ) ) };
::glLineWidth(
clamp(
0.5f * linealpha + Traction->WireThickness * Traction->radius() / 1000.f,
1.f, 1.5f ) );
// McZapkie-261102: kolor zalezy od materialu i zasniedzenia
auto const color { Traction->wire_color() };
::glColor4f( color.r, color.g, color.b, linealpha );
::glColor4fv(
glm::value_ptr(
glm::vec4{
Traction->wire_color(),
linealpha } ) );
// render
m_geometry.draw( Traction->m_geometry );
// debug data
@@ -3318,12 +3363,15 @@ opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) {
0.5f * data.area.radius + 1.f,
distance - ( 0.5f * data.area.radius ) ) :
1.f ); // negative width means the lines are always opague
::glLineWidth(
clamp(
0.5f * linealpha + data.line_width * data.area.radius / 1000.f,
1.f, 8.f ) );
::glColor4fv(
glm::value_ptr(
glm::vec4{
glm::vec3{ data.lighting.diffuse * Global::DayLight.ambient }, // w zaleznosci od koloru swiatla
std::min( 1.f, linealpha ) } ) );
::glLineWidth( clamp( 0.5f * linealpha + data.line_width * data.area.radius / 1000.f, 1.f, 8.f ) );
// render
m_geometry.draw( data.geometry );
++m_debugstats.lines;

View File

@@ -242,12 +242,9 @@ basic_cell::insert( TTrack *Path ) {
Path->RaOwnerSet( this );
#endif
// re-calculate cell radius, in case track extends outside the cell's boundaries
auto endpoints = Path->endpoints();
for( auto &endpoint : endpoints ) {
m_area.radius = std::max<float>(
m_area.radius,
glm::length( m_area.center - endpoint ) + 25.f ); // extra margin to prevent driven vehicle from flicking
}
m_area.radius = std::max(
m_area.radius,
static_cast<float>( glm::length( m_area.center - Path->location() ) + Path->radius() + 25.f ) ); // extra margin to prevent driven vehicle from flicking
}
// adds provided traction piece to the cell
@@ -258,13 +255,8 @@ basic_cell::insert( TTraction *Traction ) {
Traction->origin( m_area.center );
m_traction.emplace_back( Traction );
// re-calculate cell radius, in case traction piece extends outside the cell's boundaries
auto endpoints = Traction->endpoints();
for( auto &endpoint : endpoints ) {
m_area.radius = std::max<float>(
m_area.radius,
glm::length( m_area.center - endpoint ) ); // adding arbitrary safety margin
}
// re-calculate cell bounding area, in case traction piece extends outside the cell's boundaries
enclose_area( Traction );
}
// adds provided model instance to the cell
@@ -289,15 +281,8 @@ basic_cell::insert( TAnimModel *Instance ) {
// opaque pieces
m_instancesopaque.emplace_back( Instance );
}
// re-calculate cell radius, in case model extends outside the cell's boundaries
if( Instance->Model() ) {
auto const modelradius{ Instance->Model()->bounding_radius() };
if( modelradius > 0.f ) {
m_area.radius = std::max<float>(
m_area.radius,
glm::length( m_area.center - Instance->location() ) + modelradius ); // adding arbitrary safety margin
}
}
// re-calculate cell bounding area, in case model extends outside the cell's boundaries
enclose_area( Instance );
}
// adds provided sound instance to the cell
@@ -316,6 +301,8 @@ basic_cell::insert( TEventLauncher *Launcher ) {
m_active = true;
m_eventlaunchers.emplace_back( Launcher );
// re-calculate cell bounding area, in case launcher range extends outside the cell's boundaries
enclose_area( Launcher );
}
// registers provided path in the lookup directory of the cell
@@ -485,6 +472,15 @@ basic_cell::create_geometry( geometrybank_handle const &Bank ) {
m_geometrycreated = true; // helper for legacy animation code, get rid of it after refactoring
}
// adjusts cell bounding area to enclose specified node
void
basic_cell::enclose_area( editor::basic_node *Node ) {
m_area.radius = std::max(
m_area.radius,
static_cast<float>( glm::length( m_area.center - Node->location() ) + Node->radius() ) );
}
// legacy method, updates sounds and polls event launchers within radius around specified point
@@ -512,7 +508,7 @@ basic_section::update_traction( TDynamicObject *Vehicle, int const Pantographind
auto pantograph = Vehicle->pants[ Pantographindex ].fParamPants;
auto const pantographposition = position + ( vLeft * pantograph->vPos.z ) + ( vUp * pantograph->vPos.y ) + ( vFront * pantograph->vPos.x );
auto const radius { EU07_CELLSIZE * 0.5 };
auto const radius { EU07_CELLSIZE * 0.5 }; // redius around point of interest
for( auto &cell : m_cells ) {
// we reject early cells which aren't within our area of interest
@@ -548,6 +544,11 @@ basic_section::insert( shape_node Shape ) {
}
else {
// large, opaque shapes are placed on section level
// re-calculate section radius, in case shape geometry extends outside the section's boundaries
m_area.radius = std::max<float>(
m_area.radius,
static_cast<float>( glm::length( m_area.center - Shape.data().area.center ) + Shape.data().area.radius ) );
for( auto &shape : m_shapes ) {
// check first if the shape can't be merged with one of the shapes already present in the section
if( true == shape.merge( Shape ) ) {
@@ -739,6 +740,19 @@ basic_region::update_traction( TDynamicObject *Vehicle, int const Pantographinde
}
}
// stores content of the class in file with specified name
void
basic_region::serialize( std::string const &Scenariofile ) {
// TODO: implement
}
// restores content of the class from file with specified name. returns: true on success, false otherwise
bool
basic_region::deserialize( std::string const &Scenariofile ) {
// TODO: implement
return false;
}
// legacy method, links specified path piece with potential neighbours
void
basic_region::TrackJoin( TTrack *Track ) {
@@ -792,9 +806,9 @@ basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad, bool con
// adjust input if necessary:
if( true == Transform ) {
// shapes generated from legacy terrain come with world space coordinates and don't need processing
if( Scratchpad.location_rotation != glm::vec3( 0, 0, 0 ) ) {
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
// rotate...
auto const rotation = glm::radians( Scratchpad.location_rotation );
auto const rotation = glm::radians( Scratchpad.location.rotation );
for( auto &vertex : shape.m_data.vertices ) {
vertex.position = glm::rotateZ<double>( vertex.position, rotation.z );
vertex.position = glm::rotateX<double>( vertex.position, rotation.x );
@@ -804,10 +818,10 @@ basic_region::insert_shape( shape_node Shape, scratch_data &Scratchpad, bool con
vertex.normal = glm::rotateY( vertex.normal, rotation.y );
}
}
if( ( false == Scratchpad.location_offset.empty() )
&& ( Scratchpad.location_offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
// ...and move
auto const offset = Scratchpad.location_offset.top();
if( ( false == Scratchpad.location.offset.empty() )
&& ( Scratchpad.location.offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
// ...and move
auto const offset = Scratchpad.location.offset.top();
for( auto &vertex : shape.m_data.vertices ) {
vertex.position += offset;
}
@@ -850,19 +864,19 @@ basic_region::insert_lines( lines_node Lines, scratch_data &Scratchpad ) {
if( Lines.m_data.vertices.empty() ) { return; }
// transform point coordinates if needed
if( Scratchpad.location_rotation != glm::vec3( 0, 0, 0 ) ) {
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
// rotate...
auto const rotation = glm::radians( Scratchpad.location_rotation );
auto const rotation = glm::radians( Scratchpad.location.rotation );
for( auto &vertex : Lines.m_data.vertices ) {
vertex.position = glm::rotateZ<double>( vertex.position, rotation.z );
vertex.position = glm::rotateX<double>( vertex.position, rotation.x );
vertex.position = glm::rotateY<double>( vertex.position, rotation.y );
}
}
if( ( false == Scratchpad.location_offset.empty() )
&& ( Scratchpad.location_offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
if( ( false == Scratchpad.location.offset.empty() )
&& ( Scratchpad.location.offset.top() != glm::dvec3( 0, 0, 0 ) ) ) {
// ...and move
auto const offset = Scratchpad.location_offset.top();
auto const offset = Scratchpad.location.offset.top();
for( auto &vertex : Lines.m_data.vertices ) {
vertex.position += offset;
}
@@ -1073,7 +1087,7 @@ basic_region::sections( glm::dvec3 const &Point, float const Radius ) {
int const originx = centerx - sectioncount / 2;
int const originz = centerz - sectioncount / 2;
auto const squaredradii { std::pow( ( 0.5 * M_SQRT2 * EU07_SECTIONSIZE + 0.25 * EU07_SECTIONSIZE ) + Radius, 2 ) };
auto const padding { 0.0 }; // { EU07_SECTIONSIZE * 0.25 }; // TODO: check if we can get away with padding of 0
for( int row = originz; row <= originz + sectioncount; ++row ) {
if( row < 0 ) { continue; }
@@ -1084,7 +1098,7 @@ basic_region::sections( glm::dvec3 const &Point, float const Radius ) {
auto *section { m_sections[ row * EU07_REGIONSIDESECTIONCOUNT + column ] };
if( ( section != nullptr )
&& ( glm::length2( section->area().center - Point ) < squaredradii ) ) {
&& ( glm::length2( section->area().center - Point ) <= ( ( section->area().radius + padding + Radius ) * ( section->area().radius + padding + Radius ) ) ) ) {
m_scratchpad.sections.emplace_back( section );
}

27
scene.h
View File

@@ -29,8 +29,16 @@ int const EU07_REGIONSIDESECTIONCOUNT = 500; // number of sections along a side
struct scratch_data {
std::stack<glm::dvec3> location_offset;
glm::vec3 location_rotation;
struct binary_data {
bool terrain{ false };
} binary;
struct location_data {
std::stack<glm::dvec3> offset;
glm::vec3 rotation;
} location;
struct trainset_data {
@@ -129,6 +137,9 @@ private:
using instance_sequence = std::vector<TAnimModel *>;
using sound_sequence = std::vector<TTextSound *>;
using eventlauncher_sequence = std::vector<TEventLauncher *>;
// methods
void
enclose_area( editor::basic_node *Node );
// members
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_CELLSIZE ) };
bool m_active { false }; // whether the cell holds any actual data
@@ -182,9 +193,9 @@ public:
auto &targetcell { cell( Node->location() ) };
targetcell.insert( Node );
// some node types can extend bounding area of the target cell
m_area.radius = std::max<float>(
m_area.radius = std::max(
m_area.radius,
glm::length( m_area.center - targetcell.area().center ) + targetcell.area().radius ); }
static_cast<float>( glm::length( m_area.center - targetcell.area().center ) + targetcell.area().radius ) ); }
// registers provided node in the lookup directory of the section enclosing specified point
template <class Type_>
void
@@ -223,7 +234,7 @@ private:
cell( glm::dvec3 const &Location );
// members
// placement and visibility
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_SECTIONSIZE + 0.25 * EU07_SECTIONSIZE ) };
scene::bounding_area m_area { glm::dvec3(), static_cast<float>( 0.5 * M_SQRT2 * EU07_SECTIONSIZE ) };
// content
cell_array m_cells; // partitioning scheme
shapenode_sequence m_shapes; // large pieces of opaque geometry and (legacy) terrain
@@ -250,6 +261,12 @@ public:
// legacy method, finds and assigns traction piece to specified pantograph of provided vehicle
void
update_traction( TDynamicObject *Vehicle, int const Pantographindex );
// stores content of the class in file with specified name
void
serialize( std::string const &Scenariofile );
// restores content of the class from file with specified name. returns: true on success, false otherwise
bool
deserialize( std::string const &Scenariofile );
// legacy method, links specified path piece with potential neighbours
void
TrackJoin( TTrack *Track );

View File

@@ -259,9 +259,9 @@ shape_node::convert( TSubModel const *Submodel ) {
squareradius,
glm::length2( vertex.position - m_data.area.center ) );
}
m_data.area.radius = std::max<float>(
m_data.area.radius = std::max(
m_data.area.radius,
std::sqrt( squareradius ) );
static_cast<float>( std::sqrt( squareradius ) ) );
return *this;
}
@@ -497,5 +497,23 @@ basic_node::basic_node( scene::node_data const &Nodedata ) :
std::numeric_limits<double>::max() );
}
float const &
basic_node::radius() {
if( m_area.radius == -1.0 ) {
// calculate if needed
radius_();
}
return m_area.radius;
}
// radius() subclass details, calculates node's bounding radius
// by default nodes are 'virtual don't extend from their center point
void
basic_node::radius_() {
m_area.radius = 0.f;
}
} // editor
//---------------------------------------------------------------------------

View File

@@ -288,10 +288,12 @@ public:
return m_name; }
void
location( glm::dvec3 const Location ) {
m_location = Location; }
m_area.center = Location; }
glm::dvec3 const &
location() const {
return m_location; };
return m_area.center; };
float const &
radius();
void
visible( bool const Visible ) {
m_visible = Visible; }
@@ -300,8 +302,11 @@ public:
return m_visible; }
protected:
// methods
// radius() subclass details, calculates node's bounding radius
virtual void radius_();
// members
glm::dvec3 m_location;
scene::bounding_area m_area;
bool m_visible { true };
double m_rangesquaredmin { 0.0 }; // visibility range, min
double m_rangesquaredmax { 0.0 }; // visibility range, max

View File

@@ -38,11 +38,16 @@ state_manager::deserialize( std::string const &Scenariofile ) {
// TODO: check first for presence of serialized binary files
// if this fails, fall back on the legacy text format
scene::scratch_data importscratchpad;
importscratchpad.binary.terrain = Region->deserialize( Scenariofile );
// NOTE: for the time being import from text format is a given, since we don't have full binary serialization
cParser scenarioparser( Scenariofile, cParser::buffer_FILE, Global::asCurrentSceneryPath, Global::bLoadTraction );
if( false == scenarioparser.ok() ) { return false; }
deserialize( scenarioparser );
deserialize( scenarioparser, importscratchpad );
// if we didn't find usable binary version of the scenario files, create them now for future use
if( false == importscratchpad.binary.terrain ) { Region->serialize( Scenariofile ); }
Global::iPause &= ~0x10; // koniec pauzy wczytywania
return true;
@@ -67,9 +72,8 @@ state_manager::update( double const Deltatime, int Iterationcount ) {
// restores class data from provided stream
void
state_manager::deserialize( cParser &Input ) {
state_manager::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
scene::scratch_data importscratchpad;
// prepare deserialization function table
// since all methods use the same objects, we can have simple, hard-coded binds or lambdas for the task
using deserializefunction = void(state_manager::*)(cParser &, scene::scratch_data &);
@@ -98,7 +102,7 @@ state_manager::deserialize( cParser &Input ) {
std::string,
deserializefunctionbind> functionmap;
for( auto &function : functionlist ) {
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( importscratchpad ) ) );
functionmap.emplace( function.first, std::bind( function.second, this, std::ref( Input ), std::ref( Scratchpad ) ) );
}
// deserialize content from the provided input
@@ -127,9 +131,9 @@ state_manager::deserialize( cParser &Input ) {
token = Input.getToken<std::string>();
}
if( false == importscratchpad.initialized ) {
if( false == Scratchpad.initialized ) {
// manually perform scenario initialization
deserialize_firstinit( Input, importscratchpad );
deserialize_firstinit( Input, Scratchpad );
}
}
@@ -236,12 +240,12 @@ state_manager::deserialize_event( cParser &Input, scene::scratch_data &Scratchpa
// TODO: refactor event class and its de/serialization. do offset and rotation after deserialization is done
auto *event = new TEvent();
Math3D::vector3 offset = (
Scratchpad.location_offset.empty() ?
Scratchpad.location.offset.empty() ?
Math3D::vector3() :
Math3D::vector3(
Scratchpad.location_offset.top().x,
Scratchpad.location_offset.top().y,
Scratchpad.location_offset.top().z ) );
Scratchpad.location.offset.top().x,
Scratchpad.location.offset.top().y,
Scratchpad.location.offset.top().z ) );
event->Load( &Input, offset );
if( false == simulation::Events.insert( event ) ) {
@@ -386,20 +390,34 @@ state_manager::deserialize_node( cParser &Input, scene::scratch_data &Scratchpad
|| ( nodedata.type == "triangle_strip" )
|| ( nodedata.type == "triangle_fan" ) ) {
simulation::Region->insert_shape(
scene::shape_node().deserialize(
Input, nodedata ),
Scratchpad,
true );
if( false == Scratchpad.binary.terrain ) {
simulation::Region->insert_shape(
scene::shape_node().deserialize(
Input, nodedata ),
Scratchpad,
true );
}
else {
// all shapes were already loaded from the binary version of the file
skip_until( Input, "endtri" );
}
}
else if( ( nodedata.type == "lines" )
|| ( nodedata.type == "line_strip" )
|| ( nodedata.type == "line_loop" ) ) {
simulation::Region->insert_lines(
scene::lines_node().deserialize(
Input, nodedata ),
Scratchpad );
if( false == Scratchpad.binary.terrain ) {
simulation::Region->insert_lines(
scene::lines_node().deserialize(
Input, nodedata ),
Scratchpad );
}
else {
// all lines were already loaded from the binary version of the file
skip_until( Input, "endline" );
}
}
else if( nodedata.type == "memcell" ) {
@@ -448,18 +466,18 @@ state_manager::deserialize_origin( cParser &Input, scene::scratch_data &Scratchp
>> offset.y
>> offset.z;
// sumowanie całkowitego przesunięcia
Scratchpad.location_offset.emplace(
Scratchpad.location.offset.emplace(
offset + (
Scratchpad.location_offset.empty() ?
Scratchpad.location.offset.empty() ?
glm::dvec3() :
Scratchpad.location_offset.top() ) );
Scratchpad.location.offset.top() ) );
}
void
state_manager::deserialize_endorigin( cParser &Input, scene::scratch_data &Scratchpad ) {
if( false == Scratchpad.location_offset.empty() ) {
Scratchpad.location_offset.pop();
if( false == Scratchpad.location.offset.empty() ) {
Scratchpad.location.offset.pop();
}
else {
ErrorLog( "Bad origin: endorigin instruction with empty origin stack in file \"" + Input.Name() + "\" (line " + std::to_string( Input.Line() - 1 ) + ")" );
@@ -471,9 +489,9 @@ state_manager::deserialize_rotate( cParser &Input, scene::scratch_data &Scratchp
Input.getTokens( 3 );
Input
>> Scratchpad.location_rotation.x
>> Scratchpad.location_rotation.y
>> Scratchpad.location_rotation.z;
>> Scratchpad.location.rotation.x
>> Scratchpad.location.rotation.y
>> Scratchpad.location.rotation.z;
}
void
@@ -584,12 +602,12 @@ state_manager::deserialize_path( cParser &Input, scene::scratch_data &Scratchpad
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
auto *track = new TTrack( Nodedata );
Math3D::vector3 offset = (
Scratchpad.location_offset.empty() ?
Scratchpad.location.offset.empty() ?
Math3D::vector3() :
Math3D::vector3(
Scratchpad.location_offset.top().x,
Scratchpad.location_offset.top().y,
Scratchpad.location_offset.top().z ) );
Scratchpad.location.offset.top().x,
Scratchpad.location.offset.top().y,
Scratchpad.location.offset.top().z ) );
track->Load( &Input, offset );
return track;
@@ -605,9 +623,9 @@ state_manager::deserialize_traction( cParser &Input, scene::scratch_data &Scratc
// TODO: refactor track and wrapper classes and their de/serialization. do offset and rotation after deserialization is done
auto *traction = new TTraction( Nodedata );
auto offset = (
Scratchpad.location_offset.empty() ?
Scratchpad.location.offset.empty() ?
glm::dvec3() :
Scratchpad.location_offset.top() );
Scratchpad.location.offset.top() );
traction->Load( &Input, offset );
return traction;
@@ -670,7 +688,7 @@ state_manager::deserialize_model( cParser &Input, scene::scratch_data &Scratchpa
>> rotation.y;
auto *instance = new TAnimModel( Nodedata );
instance->RaAnglesSet( Scratchpad.location_rotation + rotation ); // dostosowanie do pochylania linii
instance->RaAnglesSet( Scratchpad.location.rotation + rotation ); // dostosowanie do pochylania linii
if( false == instance->Load( &Input, false ) ) {
// model nie wczytał się - ignorowanie node
@@ -838,12 +856,12 @@ state_manager::skip_until( cParser &Input, std::string const &Token ) {
glm::dvec3
state_manager::transform( glm::dvec3 Location, scene::scratch_data const &Scratchpad ) {
if( Scratchpad.location_rotation != glm::vec3( 0, 0, 0 ) ) {
auto const rotation = glm::radians( Scratchpad.location_rotation );
if( Scratchpad.location.rotation != glm::vec3( 0, 0, 0 ) ) {
auto const rotation = glm::radians( Scratchpad.location.rotation );
Location = glm::rotateY<double>( Location, rotation.y ); // Ra 2014-11: uwzględnienie rotacji
}
if( false == Scratchpad.location_offset.empty() ) {
Location += Scratchpad.location_offset.top();
if( false == Scratchpad.location.offset.empty() ) {
Location += Scratchpad.location.offset.top();
}
return Location;
}

View File

@@ -40,7 +40,7 @@ public:
private:
// methods
// restores class data from provided stream
void deserialize( cParser &Input );
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad );

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 17
#define VERSION_MINOR 1025
#define VERSION_MINOR 1027
#define VERSION_REVISION 0