mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
build 180809. scenery node groups, AI shunt mode braking tweaks
This commit is contained in:
11
Driver.cpp
11
Driver.cpp
@@ -4350,8 +4350,10 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
case Shunt: {
|
||||
// na jaką odleglość i z jaką predkością ma podjechać
|
||||
/*
|
||||
fMinProximityDist = 5.0;
|
||||
fMaxProximityDist = 10.0; //[m]
|
||||
|
||||
if( pVehicles[ 0 ] != pVehicles[ 1 ] ) {
|
||||
// for larger consists increase margins to account for slower braking etc
|
||||
// NOTE: this will affect also multi-unit vehicles TBD: is this what we want?
|
||||
@@ -4367,6 +4369,15 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
fMinProximityDist = std::min( 5 + iVehicles, 25 );
|
||||
fMaxProximityDist = std::min( 10 + iVehicles, 50 );
|
||||
if( ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 )
|
||||
&& ( fBrake_a0[ 0 ] >= 0.35 ) ) {
|
||||
// cargo trains with high braking threshold may require even larger safety margin
|
||||
fMaxProximityDist *= 1.5;
|
||||
}
|
||||
|
||||
fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||||
// margines prędkości powodujący załączenie napędu
|
||||
// były problemy z jazdą np. 3km/h podczas ładowania wagonów
|
||||
|
||||
@@ -224,7 +224,7 @@ int TSubModel::Load( cParser &parser, TModel3d *Model, /*int Pos,*/ bool dynamic
|
||||
f4Specular = glm::vec4{ 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
}
|
||||
}
|
||||
parser.ignoreTokens(1); // zignorowanie nazwy "SelfIllum:"
|
||||
parser.ignoreToken(); // zignorowanie nazwy "SelfIllum:"
|
||||
{
|
||||
std::string light = parser.getToken<std::string>();
|
||||
if (light == "true")
|
||||
|
||||
96
Train.cpp
96
Train.cpp
@@ -22,6 +22,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "Logs.h"
|
||||
#include "MdlMngr.h"
|
||||
#include "model3d.h"
|
||||
#include "dumb3d.h"
|
||||
#include "Timer.h"
|
||||
#include "Driver.h"
|
||||
#include "dynobj.h"
|
||||
@@ -6243,7 +6244,7 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
}
|
||||
std::string cabstr("cab" + std::to_string(cabindex) + "definition:");
|
||||
|
||||
std::shared_ptr<cParser> parser = std::make_shared<cParser>(asFileName, cParser::buffer_FILE);
|
||||
cParser parser(asFileName, cParser::buffer_FILE);
|
||||
// NOTE: yaml-style comments are disabled until conflict in use of # is resolved
|
||||
// parser.addCommentStyle( "#", "\n" );
|
||||
std::string token;
|
||||
@@ -6251,11 +6252,45 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
{
|
||||
// szukanie kabiny
|
||||
token = "";
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
/*
|
||||
if( token == "locations:" ) {
|
||||
do {
|
||||
token = "";
|
||||
parser.getTokens(); parser >> token;
|
||||
|
||||
if( token == "radio:" ) {
|
||||
// point in 3d space, in format [ x, y, z ]
|
||||
glm::vec3 radiolocation;
|
||||
parser.getTokens( 3, false, "\n\r\t ,;[]" );
|
||||
parser
|
||||
>> radiolocation.x
|
||||
>> radiolocation.y
|
||||
>> radiolocation.z;
|
||||
radiolocation *= glm::vec3( NewCabNo, 1, NewCabNo );
|
||||
m_radiosound.offset( radiolocation );
|
||||
}
|
||||
|
||||
else if( token == "alerter:" ) {
|
||||
// point in 3d space, in format [ x, y, z ]
|
||||
glm::vec3 alerterlocation;
|
||||
parser.getTokens( 3, false, "\n\r\t ,;[]" );
|
||||
parser
|
||||
>> alerterlocation.x
|
||||
>> alerterlocation.y
|
||||
>> alerterlocation.z;
|
||||
alerterlocation *= glm::vec3( NewCabNo, 1, NewCabNo );
|
||||
dsbBuzzer.offset( alerterlocation );
|
||||
}
|
||||
|
||||
} while( ( token != "" )
|
||||
&& ( token != "endlocations" ) );
|
||||
|
||||
} // locations:
|
||||
*/
|
||||
} while ((token != "") && (token != cabstr));
|
||||
|
||||
/*
|
||||
if ((cabindex != 1) && (token != cabstr))
|
||||
{
|
||||
// jeśli nie znaleziony wpis kabiny, próba szukania kabiny 1
|
||||
@@ -6267,65 +6302,66 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
do
|
||||
{
|
||||
token = "";
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
} while ((token != "") && (token != cabstr));
|
||||
}
|
||||
*/
|
||||
if (token == cabstr)
|
||||
{
|
||||
// jeśli znaleziony wpis kabiny
|
||||
Cabine[cabindex].Load(*parser);
|
||||
Cabine[cabindex].Load(parser);
|
||||
// NOTE: the position and angle definitions depend on strict entry order
|
||||
// TODO: refactor into more flexible arrangement
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) {
|
||||
// camera view angle
|
||||
parser->getTokens( 2, false );
|
||||
parser.getTokens( 2, false );
|
||||
// angle is specified in degrees but internally stored in radians
|
||||
glm::vec2 viewangle;
|
||||
*parser
|
||||
parser
|
||||
>> viewangle.y // yaw first, then pitch
|
||||
>> viewangle.x;
|
||||
pMechViewAngle = glm::radians( viewangle );
|
||||
Global.pCamera.Pitch = pMechViewAngle.x;
|
||||
Global.pCamera.Yaw = pMechViewAngle.y;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
}
|
||||
if (token == std::string("driver" + std::to_string(cabindex) + "pos:"))
|
||||
{
|
||||
// pozycja poczatkowa maszynisty
|
||||
parser->getTokens(3, false);
|
||||
*parser
|
||||
parser.getTokens(3, false);
|
||||
parser
|
||||
>> pMechOffset.x
|
||||
>> pMechOffset.y
|
||||
>> pMechOffset.z;
|
||||
pMechSittingPosition = pMechOffset;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
}
|
||||
// ABu: pozycja siedzaca mechanika
|
||||
if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:"))
|
||||
{
|
||||
// ABu 180404 pozycja siedzaca maszynisty
|
||||
parser->getTokens(3, false);
|
||||
*parser
|
||||
parser.getTokens(3, false);
|
||||
parser
|
||||
>> pMechSittingPosition.x
|
||||
>> pMechSittingPosition.y
|
||||
>> pMechSittingPosition.z;
|
||||
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
}
|
||||
// else parse=false;
|
||||
do {
|
||||
if( parse == true ) {
|
||||
token = "";
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
}
|
||||
else {
|
||||
parse = true;
|
||||
@@ -6338,8 +6374,8 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
if (token == std::string("cab" + std::to_string(cabindex) + "model:"))
|
||||
{
|
||||
// model kabiny
|
||||
parser->getTokens();
|
||||
*parser >> token;
|
||||
parser.getTokens();
|
||||
parser >> token;
|
||||
if (token != "none")
|
||||
{
|
||||
// bieżąca sciezka do tekstur to dynamic/...
|
||||
@@ -6375,19 +6411,19 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
// don't bother with other parts until the cab is initialised
|
||||
continue;
|
||||
}
|
||||
else if (true == initialize_gauge(*parser, token, cabindex))
|
||||
else if (true == initialize_gauge(parser, token, cabindex))
|
||||
{
|
||||
// matched the token, grab the next one
|
||||
continue;
|
||||
}
|
||||
else if (true == initialize_button(*parser, token, cabindex))
|
||||
else if (true == initialize_button(parser, token, cabindex))
|
||||
{
|
||||
// matched the token, grab the next one
|
||||
continue;
|
||||
}
|
||||
else if (token == "pyscreen:")
|
||||
{
|
||||
pyScreens.init(*parser, DynamicObject->mdKabina, DynamicObject->name(), NewCabNo);
|
||||
pyScreens.init(parser, DynamicObject->mdKabina, DynamicObject->name(), NewCabNo);
|
||||
}
|
||||
// btLampkaUnknown.Init("unknown",mdKabina,false);
|
||||
} while (token != "");
|
||||
@@ -6415,10 +6451,10 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
||||
}
|
||||
// radio has two potential items which can provide the position
|
||||
if( m_radiosound.offset() == nullvector ) {
|
||||
m_radiosound.offset( ggRadioButton.model_offset() );
|
||||
m_radiosound.offset( btLampkaRadio.model_offset() );
|
||||
}
|
||||
if( m_radiosound.offset() == nullvector ) {
|
||||
m_radiosound.offset( btLampkaRadio.model_offset() );
|
||||
m_radiosound.offset( ggRadioButton.model_offset() );
|
||||
}
|
||||
if( m_radiostop.offset() == nullvector ) {
|
||||
m_radiostop.offset( m_radiosound.offset() );
|
||||
|
||||
@@ -303,6 +303,9 @@
|
||||
<ClCompile Include="keyboardinput.cpp">
|
||||
<Filter>Source Files\application\input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="scenenodegroups.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Globals.h">
|
||||
@@ -572,6 +575,9 @@
|
||||
<ClInclude Include="keyboardinput.h">
|
||||
<Filter>Header Files\application\input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="scenenodegroups.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="maszyna.rc">
|
||||
|
||||
19
parser.cpp
19
parser.cpp
@@ -9,8 +9,11 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "parser.h"
|
||||
#include "utilities.h"
|
||||
#include "logs.h"
|
||||
|
||||
#include "scenenodegroups.h"
|
||||
|
||||
/*
|
||||
MaSzyna EU07 locomotive simulator parser
|
||||
Copyright (C) 2003 TOLARIS
|
||||
@@ -24,11 +27,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction, std::vector<std::string> Parameters ) :
|
||||
mPath(Path),
|
||||
LoadTraction( Loadtraction ) {
|
||||
// build comments map
|
||||
mComments.insert(commentmap::value_type("/*", "*/"));
|
||||
mComments.insert(commentmap::value_type("//", "\n"));
|
||||
// mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane
|
||||
|
||||
// store to calculate sub-sequent includes from relative path
|
||||
if( Type == buffertype::buffer_FILE ) {
|
||||
mFile = Stream;
|
||||
@@ -38,6 +36,12 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
|
||||
case buffer_FILE: {
|
||||
Path.append( Stream );
|
||||
mStream = std::make_shared<std::ifstream>( Path );
|
||||
// content of *.inc files is potentially grouped together
|
||||
if( ( Stream.size() >= 4 )
|
||||
&& ( ToLower( Stream.substr( Stream.size() - 4 ) ) == ".inc" ) ) {
|
||||
mIncFile = true;
|
||||
scene::Groups.begin();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case buffer_TEXT: {
|
||||
@@ -69,7 +73,10 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
|
||||
// destructor
|
||||
cParser::~cParser() {
|
||||
|
||||
mComments.clear();
|
||||
if( true == mIncFile ) {
|
||||
// wrap up the node group holding content of processed file
|
||||
scene::Groups.end();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
12
parser.h
12
parser.h
@@ -47,11 +47,6 @@ class cParser //: public std::stringstream
|
||||
ignoreToken() {
|
||||
readToken(); };
|
||||
inline
|
||||
void
|
||||
ignoreTokens(int count) {
|
||||
for( int i = 0; i < count; ++i ) {
|
||||
readToken(); } };
|
||||
inline
|
||||
bool
|
||||
expectToken( std::string const &Value ) {
|
||||
return readToken() == Value; };
|
||||
@@ -97,14 +92,17 @@ class cParser //: public std::stringstream
|
||||
std::size_t count();
|
||||
// members:
|
||||
bool m_autoclear { true }; // not retrieved tokens are discarded when another read command is issued (legacy behaviour)
|
||||
bool LoadTraction; // load traction?
|
||||
bool LoadTraction { true }; // load traction?
|
||||
std::shared_ptr<std::istream> mStream; // relevant kind of buffer is attached on creation.
|
||||
std::string mFile; // name of the open file, if any
|
||||
std::string mPath; // path to open stream, for relative path lookups.
|
||||
std::streamoff mSize { 0 }; // size of open stream, for progress report.
|
||||
std::size_t mLine { 0 }; // currently processed line
|
||||
bool mIncFile { false }; // the parser is processing an *.inc file
|
||||
typedef std::map<std::string, std::string> commentmap;
|
||||
commentmap mComments;
|
||||
commentmap mComments {
|
||||
commentmap::value_type( "/*", "*/" ),
|
||||
commentmap::value_type( "//", "\n" ) };
|
||||
std::shared_ptr<cParser> mIncludeParser; // child class to handle include directives.
|
||||
std::vector<std::string> parameters; // parameter list for included file.
|
||||
std::deque<std::string> tokens;
|
||||
|
||||
126
sceneeditor.cpp
126
sceneeditor.cpp
@@ -9,6 +9,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "sceneeditor.h"
|
||||
#include "scenenodegroups.h"
|
||||
|
||||
#include "globals.h"
|
||||
#include "application.h"
|
||||
@@ -22,20 +23,26 @@ namespace scene {
|
||||
void
|
||||
basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) {
|
||||
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
|
||||
auto location { Location };
|
||||
auto const initiallocation { Node->location() };
|
||||
auto targetlocation { Location };
|
||||
if( false == Snaptoground ) {
|
||||
location.y = node->location().y;
|
||||
targetlocation.y = initiallocation.y;
|
||||
}
|
||||
// NOTE: bit of a waste for single nodes, for the sake of less varied code down the road
|
||||
auto const translation { targetlocation - initiallocation };
|
||||
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
translate_instance( static_cast<TAnimModel *>( node ), location );
|
||||
if( Node->group() == null_handle ) {
|
||||
translate_node( Node, Node->location() + translation );
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
||||
translate_memorycell( static_cast<TMemCell *>( node ), location );
|
||||
else {
|
||||
// translate entire group
|
||||
// TODO: contextual switch between group and item translation
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
[&]( auto *node ) {
|
||||
translate_node( node, node->location() + translation ); } );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
@@ -44,15 +51,41 @@ basic_editor::translate( scene::basic_node *Node, float const Offset ) {
|
||||
// NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group
|
||||
auto location { Node->location() };
|
||||
auto const distance { glm::length( location - glm::dvec3{ Global.pCamera.Pos } ) };
|
||||
auto const offset { Offset * std::max( 1.0, distance * 0.01 ) };
|
||||
auto const offset { static_cast<float>( Offset * std::max( 1.0, distance * 0.01 ) ) };
|
||||
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
translate_instance( static_cast<TAnimModel *>( node ), offset );
|
||||
if( Node->group() == null_handle ) {
|
||||
translate_node( Node, offset );
|
||||
}
|
||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
||||
translate_memorycell( static_cast<TMemCell *>( node ), offset );
|
||||
else {
|
||||
// translate entire group
|
||||
// TODO: contextual switch between group and item translation
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
[&]( auto *node ) {
|
||||
translate_node( node, offset ); } );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::translate_node( scene::basic_node *Node, glm::dvec3 const &Location ) {
|
||||
|
||||
if( typeid( *Node ) == typeid( TAnimModel ) ) {
|
||||
translate_instance( static_cast<TAnimModel *>( Node ), Location );
|
||||
}
|
||||
else if( typeid( *Node ) == typeid( TMemCell ) ) {
|
||||
translate_memorycell( static_cast<TMemCell *>( Node ), Location );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::translate_node( scene::basic_node *Node, float const Offset ) {
|
||||
|
||||
if( typeid( *Node ) == typeid( TAnimModel ) ) {
|
||||
translate_instance( static_cast<TAnimModel *>( Node ), Offset );
|
||||
}
|
||||
else if( typeid( *Node ) == typeid( TMemCell ) ) {
|
||||
translate_memorycell( static_cast<TMemCell *>( Node ), Offset );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,25 +124,62 @@ basic_editor::translate_memorycell( TMemCell *Memorycell, float const Offset ) {
|
||||
void
|
||||
basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ) {
|
||||
|
||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
||||
glm::vec3 rotation { 0, Angle.y, 0 };
|
||||
|
||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
||||
rotate_instance( static_cast<TAnimModel *>( node ), Angle, Quantization );
|
||||
// quantize resulting angle if requested and type of the node allows it
|
||||
// TBD, TODO: angle quantization for types other than instanced models
|
||||
if( ( Quantization > 0.f )
|
||||
&& ( typeid( *Node ) == typeid( TAnimModel ) ) ) {
|
||||
|
||||
auto const initialangle { static_cast<TAnimModel *>( Node )->Angles() };
|
||||
rotation += initialangle;
|
||||
|
||||
// TBD, TODO: adjustable quantization step
|
||||
rotation.y = quantize( rotation.y, Quantization );
|
||||
|
||||
rotation -= initialangle;
|
||||
}
|
||||
|
||||
if( Node->group() == null_handle ) {
|
||||
rotate_node( Node, rotation );
|
||||
}
|
||||
else {
|
||||
// rotate entire group
|
||||
// TODO: contextual switch between group and item rotation
|
||||
auto const rotationcenter { Node->location() };
|
||||
auto nodegroup { scene::Groups.group( Node->group() ) };
|
||||
std::for_each(
|
||||
nodegroup.first, nodegroup.second,
|
||||
[&]( auto *node ) {
|
||||
rotate_node( node, rotation );
|
||||
if( node != Node ) {
|
||||
translate_node(
|
||||
node,
|
||||
rotationcenter
|
||||
+ glm::rotateY(
|
||||
node->location() - rotationcenter,
|
||||
glm::radians<double>( rotation.y ) ) ); } } );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization ) {
|
||||
basic_editor::rotate_node( scene::basic_node *Node, glm::vec3 const &Angle ) {
|
||||
|
||||
// adjust node data
|
||||
glm::vec3 angle = glm::dvec3 { Instance->Angles() };
|
||||
angle.y = clamp_circular( angle.y + Angle.y, 360.f );
|
||||
if( Quantization > 0.f ) {
|
||||
// TBD, TODO: adjustable quantization step
|
||||
angle.y = quantize( angle.y, Quantization );
|
||||
if( typeid( *Node ) == typeid( TAnimModel ) ) {
|
||||
rotate_instance( static_cast<TAnimModel *>( Node ), Angle );
|
||||
}
|
||||
Instance->Angles( angle );
|
||||
// update scene
|
||||
}
|
||||
|
||||
void
|
||||
basic_editor::rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle ) {
|
||||
|
||||
auto targetangle { Instance->Angles() + Angle };
|
||||
|
||||
targetangle.x = clamp_circular( targetangle.x, 360.f );
|
||||
targetangle.y = clamp_circular( targetangle.y, 360.f );
|
||||
targetangle.z = clamp_circular( targetangle.z, 360.f );
|
||||
|
||||
Instance->Angles( targetangle );
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
@@ -36,6 +36,15 @@ public:
|
||||
translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground );
|
||||
void
|
||||
translate( scene::basic_node *Node, float const Offset );
|
||||
void
|
||||
rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization );
|
||||
|
||||
private:
|
||||
// methods
|
||||
void
|
||||
translate_node( scene::basic_node *Node, glm::dvec3 const &Location );
|
||||
void
|
||||
translate_node( scene::basic_node *Node, float const Offset );
|
||||
void
|
||||
translate_instance( TAnimModel *Instance, glm::dvec3 const &Location );
|
||||
void
|
||||
@@ -45,9 +54,9 @@ public:
|
||||
void
|
||||
translate_memorycell( TMemCell *Memorycell, float const Offset );
|
||||
void
|
||||
rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization );
|
||||
rotate_node( scene::basic_node *Node, glm::vec3 const &Angle );
|
||||
void
|
||||
rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization );
|
||||
rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle );
|
||||
};
|
||||
|
||||
} // scene
|
||||
|
||||
19
scenenode.h
19
scenenode.h
@@ -64,6 +64,8 @@ struct bounding_area {
|
||||
deserialize( std::istream &Input );
|
||||
};
|
||||
|
||||
using group_handle = std::size_t;
|
||||
|
||||
struct node_data {
|
||||
|
||||
double range_min { 0.0 };
|
||||
@@ -330,9 +332,14 @@ public:
|
||||
visible( bool const Visible );
|
||||
bool
|
||||
visible() const;
|
||||
void
|
||||
group( scene::group_handle Group );
|
||||
scene::group_handle
|
||||
group() const;
|
||||
|
||||
protected:
|
||||
// members
|
||||
scene::group_handle m_group { null_handle }; // group this node belongs to, if any
|
||||
scene::bounding_area m_area;
|
||||
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||
@@ -381,6 +388,18 @@ basic_node::visible() const {
|
||||
return m_visible;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
basic_node::group( scene::group_handle Group ) {
|
||||
m_group = Group;
|
||||
}
|
||||
|
||||
inline
|
||||
scene::group_handle
|
||||
basic_node::group() const {
|
||||
return m_group;
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
97
scenenodegroups.cpp
Normal file
97
scenenodegroups.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "scenenodegroups.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
node_groups Groups;
|
||||
|
||||
// requests creation of a new node group. returns: handle to the group
|
||||
scene::group_handle
|
||||
node_groups::begin() {
|
||||
|
||||
m_activegroup.push( create_handle() );
|
||||
|
||||
return handle();
|
||||
}
|
||||
|
||||
// indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty
|
||||
scene::group_handle
|
||||
node_groups::end() {
|
||||
|
||||
if( false == m_activegroup.empty() ) {
|
||||
|
||||
auto const closinggroup { m_activegroup.top() };
|
||||
m_activegroup.pop();
|
||||
// if the completed group holds only one item and there's no chance more items will be added, disband it
|
||||
if( ( true == m_activegroup.empty() )
|
||||
|| ( m_activegroup.top() != closinggroup ) ) {
|
||||
|
||||
auto lookup { m_groupmap.find( closinggroup ) };
|
||||
if( ( lookup != m_groupmap.end() )
|
||||
&& ( lookup->second.size() <= 1 ) ) {
|
||||
|
||||
erase( lookup );
|
||||
}
|
||||
}
|
||||
}
|
||||
return handle();
|
||||
}
|
||||
|
||||
// returns current active group, or null_handle if group stack is empty
|
||||
group_handle
|
||||
node_groups::handle() const {
|
||||
|
||||
return (
|
||||
m_activegroup.empty() ?
|
||||
null_handle :
|
||||
m_activegroup.top() );
|
||||
}
|
||||
|
||||
// places provided node in specified group
|
||||
void
|
||||
node_groups::register_node( scene::basic_node *Node, scene::group_handle const Group ) {
|
||||
|
||||
// TBD, TODO: automatically unregister the node from its current group?
|
||||
Node->group( Group );
|
||||
|
||||
if( Group == null_handle ) { return; }
|
||||
|
||||
auto &nodesequence { m_groupmap[ Group ] };
|
||||
if( std::find( std::begin( nodesequence ), std::end( nodesequence ), Node ) == std::end( nodesequence ) ) {
|
||||
// don't add the same node twice
|
||||
nodesequence.emplace_back( Node );
|
||||
}
|
||||
}
|
||||
|
||||
// removes specified group from the group list and group information from the group's nodes
|
||||
void
|
||||
node_groups::erase( group_map::const_iterator Group ) {
|
||||
|
||||
for( auto *node : Group->second ) {
|
||||
node->group( null_handle );
|
||||
}
|
||||
m_groupmap.erase( Group );
|
||||
}
|
||||
|
||||
// creates handle for a new group
|
||||
group_handle
|
||||
node_groups::create_handle() {
|
||||
// NOTE: for simplification nested group structure are flattened
|
||||
return(
|
||||
m_activegroup.empty() ?
|
||||
m_groupmap.size() + 1 : // new group isn't created until node registration
|
||||
m_activegroup.top() );
|
||||
}
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
64
scenenodegroups.h
Normal file
64
scenenodegroups.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "scenenode.h"
|
||||
|
||||
namespace scene {
|
||||
|
||||
// holds lists of grouped scene nodes
|
||||
class node_groups {
|
||||
// NOTE: during scenario deserialization encountering *.inc file causes creation of a new group on the group stack
|
||||
// this allows all nodes listed in this *.inc file to be grouped and potentially modified together by the editor.
|
||||
private:
|
||||
// types
|
||||
using node_sequence = std::vector<scene::basic_node *>;
|
||||
|
||||
public:
|
||||
// constructors
|
||||
node_groups() = default;
|
||||
// methods
|
||||
// requests creation of a new node group. returns: handle to the group
|
||||
group_handle
|
||||
begin();
|
||||
// indicates creation of current group ended. returns: handle to the parent group or null_handle if group stack is empty
|
||||
group_handle
|
||||
end();
|
||||
// returns current active group, or null_handle if group stack is empty
|
||||
group_handle
|
||||
handle() const;
|
||||
// places provided node in specified group
|
||||
void
|
||||
register_node( scene::basic_node *Node, scene::group_handle const Group );
|
||||
std::pair<node_sequence::iterator, node_sequence::iterator>
|
||||
group( scene::group_handle const Group ) {
|
||||
auto &group { m_groupmap[ Group ] };
|
||||
return { std::begin( group ), std::end( group ) }; }
|
||||
|
||||
private:
|
||||
// types
|
||||
using group_map = std::unordered_map<scene::group_handle, node_sequence>;
|
||||
// methods
|
||||
// removes specified group from the group list and group information from the group's nodes
|
||||
void
|
||||
erase( group_map::const_iterator Group );
|
||||
// creates handle for a new group
|
||||
group_handle
|
||||
create_handle();
|
||||
// members
|
||||
group_map m_groupmap; // map of established node groups
|
||||
std::stack<scene::group_handle> m_activegroup; // helper, group to be assigned to newly created nodes
|
||||
};
|
||||
|
||||
extern node_groups Groups;
|
||||
|
||||
} // scene
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -15,6 +15,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "globals.h"
|
||||
#include "simulation.h"
|
||||
#include "simulationtime.h"
|
||||
#include "scenenodegroups.h"
|
||||
#include "event.h"
|
||||
#include "driver.h"
|
||||
#include "dynobj.h"
|
||||
@@ -304,6 +305,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
delete pathnode;
|
||||
*/
|
||||
}
|
||||
scene::Groups.register_node( path, scene::Groups.handle() );
|
||||
simulation::Region->insert_and_register( path );
|
||||
}
|
||||
else if( nodedata.type == "traction" ) {
|
||||
@@ -315,6 +317,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
if( false == simulation::Traction.insert( traction ) ) {
|
||||
ErrorLog( "Bad scenario: traction piece with duplicate name \"" + traction->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
scene::Groups.register_node( traction, scene::Groups.handle() );
|
||||
simulation::Region->insert_and_register( traction );
|
||||
}
|
||||
else if( nodedata.type == "tractionpowersource" ) {
|
||||
@@ -375,6 +378,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
if( false == simulation::Instances.insert( instance ) ) {
|
||||
ErrorLog( "Bad scenario: 3d model instance with duplicate name \"" + instance->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
scene::Groups.register_node( instance, scene::Groups.handle() );
|
||||
simulation::Region->insert( instance );
|
||||
}
|
||||
}
|
||||
@@ -417,6 +421,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
||||
ErrorLog( "Bad scenario: memory memorycell with duplicate name \"" + memorycell->name() + "\" encountered in file \"" + Input.Name() + "\" (line " + std::to_string( inputline ) + ")" );
|
||||
}
|
||||
scene::Groups.register_node( memorycell, scene::Groups.handle() );
|
||||
simulation::Region->insert( memorycell );
|
||||
}
|
||||
else if( nodedata.type == "eventlauncher" ) {
|
||||
@@ -431,6 +436,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
||||
simulation::Events.queue( eventlauncher );
|
||||
}
|
||||
else {
|
||||
scene::Groups.register_node( eventlauncher, scene::Groups.handle() );
|
||||
simulation::Region->insert( eventlauncher );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user