mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-17 23:39:18 +02: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: {
|
case Shunt: {
|
||||||
// na jaką odleglość i z jaką predkością ma podjechać
|
// na jaką odleglość i z jaką predkością ma podjechać
|
||||||
|
/*
|
||||||
fMinProximityDist = 5.0;
|
fMinProximityDist = 5.0;
|
||||||
fMaxProximityDist = 10.0; //[m]
|
fMaxProximityDist = 10.0; //[m]
|
||||||
|
|
||||||
if( pVehicles[ 0 ] != pVehicles[ 1 ] ) {
|
if( pVehicles[ 0 ] != pVehicles[ 1 ] ) {
|
||||||
// for larger consists increase margins to account for slower braking etc
|
// 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?
|
// 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
|
fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||||||
// margines prędkości powodujący załączenie napędu
|
// margines prędkości powodujący załączenie napędu
|
||||||
// były problemy z jazdą np. 3km/h podczas ładowania wagonów
|
// 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 };
|
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>();
|
std::string light = parser.getToken<std::string>();
|
||||||
if (light == "true")
|
if (light == "true")
|
||||||
|
|||||||
96
Train.cpp
96
Train.cpp
@@ -22,6 +22,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "Logs.h"
|
#include "Logs.h"
|
||||||
#include "MdlMngr.h"
|
#include "MdlMngr.h"
|
||||||
#include "model3d.h"
|
#include "model3d.h"
|
||||||
|
#include "dumb3d.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Driver.h"
|
#include "Driver.h"
|
||||||
#include "dynobj.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::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
|
// NOTE: yaml-style comments are disabled until conflict in use of # is resolved
|
||||||
// parser.addCommentStyle( "#", "\n" );
|
// parser.addCommentStyle( "#", "\n" );
|
||||||
std::string token;
|
std::string token;
|
||||||
@@ -6251,11 +6252,45 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
|
|||||||
{
|
{
|
||||||
// szukanie kabiny
|
// szukanie kabiny
|
||||||
token = "";
|
token = "";
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
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));
|
} while ((token != "") && (token != cabstr));
|
||||||
|
/*
|
||||||
if ((cabindex != 1) && (token != cabstr))
|
if ((cabindex != 1) && (token != cabstr))
|
||||||
{
|
{
|
||||||
// jeśli nie znaleziony wpis kabiny, próba szukania kabiny 1
|
// 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
|
do
|
||||||
{
|
{
|
||||||
token = "";
|
token = "";
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
} while ((token != "") && (token != cabstr));
|
} while ((token != "") && (token != cabstr));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (token == cabstr)
|
if (token == cabstr)
|
||||||
{
|
{
|
||||||
// jeśli znaleziony wpis kabiny
|
// jeśli znaleziony wpis kabiny
|
||||||
Cabine[cabindex].Load(*parser);
|
Cabine[cabindex].Load(parser);
|
||||||
// NOTE: the position and angle definitions depend on strict entry order
|
// NOTE: the position and angle definitions depend on strict entry order
|
||||||
// TODO: refactor into more flexible arrangement
|
// TODO: refactor into more flexible arrangement
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) {
|
if( token == std::string( "driver" + std::to_string( cabindex ) + "angle:" ) ) {
|
||||||
// camera view angle
|
// camera view angle
|
||||||
parser->getTokens( 2, false );
|
parser.getTokens( 2, false );
|
||||||
// angle is specified in degrees but internally stored in radians
|
// angle is specified in degrees but internally stored in radians
|
||||||
glm::vec2 viewangle;
|
glm::vec2 viewangle;
|
||||||
*parser
|
parser
|
||||||
>> viewangle.y // yaw first, then pitch
|
>> viewangle.y // yaw first, then pitch
|
||||||
>> viewangle.x;
|
>> viewangle.x;
|
||||||
pMechViewAngle = glm::radians( viewangle );
|
pMechViewAngle = glm::radians( viewangle );
|
||||||
Global.pCamera.Pitch = pMechViewAngle.x;
|
Global.pCamera.Pitch = pMechViewAngle.x;
|
||||||
Global.pCamera.Yaw = pMechViewAngle.y;
|
Global.pCamera.Yaw = pMechViewAngle.y;
|
||||||
|
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
}
|
}
|
||||||
if (token == std::string("driver" + std::to_string(cabindex) + "pos:"))
|
if (token == std::string("driver" + std::to_string(cabindex) + "pos:"))
|
||||||
{
|
{
|
||||||
// pozycja poczatkowa maszynisty
|
// pozycja poczatkowa maszynisty
|
||||||
parser->getTokens(3, false);
|
parser.getTokens(3, false);
|
||||||
*parser
|
parser
|
||||||
>> pMechOffset.x
|
>> pMechOffset.x
|
||||||
>> pMechOffset.y
|
>> pMechOffset.y
|
||||||
>> pMechOffset.z;
|
>> pMechOffset.z;
|
||||||
pMechSittingPosition = pMechOffset;
|
pMechSittingPosition = pMechOffset;
|
||||||
|
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
}
|
}
|
||||||
// ABu: pozycja siedzaca mechanika
|
// ABu: pozycja siedzaca mechanika
|
||||||
if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:"))
|
if (token == std::string("driver" + std::to_string(cabindex) + "sitpos:"))
|
||||||
{
|
{
|
||||||
// ABu 180404 pozycja siedzaca maszynisty
|
// ABu 180404 pozycja siedzaca maszynisty
|
||||||
parser->getTokens(3, false);
|
parser.getTokens(3, false);
|
||||||
*parser
|
parser
|
||||||
>> pMechSittingPosition.x
|
>> pMechSittingPosition.x
|
||||||
>> pMechSittingPosition.y
|
>> pMechSittingPosition.y
|
||||||
>> pMechSittingPosition.z;
|
>> pMechSittingPosition.z;
|
||||||
|
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
}
|
}
|
||||||
// else parse=false;
|
// else parse=false;
|
||||||
do {
|
do {
|
||||||
if( parse == true ) {
|
if( parse == true ) {
|
||||||
token = "";
|
token = "";
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parse = true;
|
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:"))
|
if (token == std::string("cab" + std::to_string(cabindex) + "model:"))
|
||||||
{
|
{
|
||||||
// model kabiny
|
// model kabiny
|
||||||
parser->getTokens();
|
parser.getTokens();
|
||||||
*parser >> token;
|
parser >> token;
|
||||||
if (token != "none")
|
if (token != "none")
|
||||||
{
|
{
|
||||||
// bieżąca sciezka do tekstur to dynamic/...
|
// 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
|
// don't bother with other parts until the cab is initialised
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (true == initialize_gauge(*parser, token, cabindex))
|
else if (true == initialize_gauge(parser, token, cabindex))
|
||||||
{
|
{
|
||||||
// matched the token, grab the next one
|
// matched the token, grab the next one
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (true == initialize_button(*parser, token, cabindex))
|
else if (true == initialize_button(parser, token, cabindex))
|
||||||
{
|
{
|
||||||
// matched the token, grab the next one
|
// matched the token, grab the next one
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (token == "pyscreen:")
|
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);
|
// btLampkaUnknown.Init("unknown",mdKabina,false);
|
||||||
} while (token != "");
|
} 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
|
// radio has two potential items which can provide the position
|
||||||
if( m_radiosound.offset() == nullvector ) {
|
if( m_radiosound.offset() == nullvector ) {
|
||||||
m_radiosound.offset( ggRadioButton.model_offset() );
|
m_radiosound.offset( btLampkaRadio.model_offset() );
|
||||||
}
|
}
|
||||||
if( m_radiosound.offset() == nullvector ) {
|
if( m_radiosound.offset() == nullvector ) {
|
||||||
m_radiosound.offset( btLampkaRadio.model_offset() );
|
m_radiosound.offset( ggRadioButton.model_offset() );
|
||||||
}
|
}
|
||||||
if( m_radiostop.offset() == nullvector ) {
|
if( m_radiostop.offset() == nullvector ) {
|
||||||
m_radiostop.offset( m_radiosound.offset() );
|
m_radiostop.offset( m_radiosound.offset() );
|
||||||
|
|||||||
@@ -303,6 +303,9 @@
|
|||||||
<ClCompile Include="keyboardinput.cpp">
|
<ClCompile Include="keyboardinput.cpp">
|
||||||
<Filter>Source Files\application\input</Filter>
|
<Filter>Source Files\application\input</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="scenenodegroups.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Globals.h">
|
<ClInclude Include="Globals.h">
|
||||||
@@ -572,6 +575,9 @@
|
|||||||
<ClInclude Include="keyboardinput.h">
|
<ClInclude Include="keyboardinput.h">
|
||||||
<Filter>Header Files\application\input</Filter>
|
<Filter>Header Files\application\input</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="scenenodegroups.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="maszyna.rc">
|
<ResourceCompile Include="maszyna.rc">
|
||||||
|
|||||||
19
parser.cpp
19
parser.cpp
@@ -9,8 +9,11 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "utilities.h"
|
||||||
#include "logs.h"
|
#include "logs.h"
|
||||||
|
|
||||||
|
#include "scenenodegroups.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MaSzyna EU07 locomotive simulator parser
|
MaSzyna EU07 locomotive simulator parser
|
||||||
Copyright (C) 2003 TOLARIS
|
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 ) :
|
cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction, std::vector<std::string> Parameters ) :
|
||||||
mPath(Path),
|
mPath(Path),
|
||||||
LoadTraction( Loadtraction ) {
|
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
|
// store to calculate sub-sequent includes from relative path
|
||||||
if( Type == buffertype::buffer_FILE ) {
|
if( Type == buffertype::buffer_FILE ) {
|
||||||
mFile = Stream;
|
mFile = Stream;
|
||||||
@@ -38,6 +36,12 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
|
|||||||
case buffer_FILE: {
|
case buffer_FILE: {
|
||||||
Path.append( Stream );
|
Path.append( Stream );
|
||||||
mStream = std::make_shared<std::ifstream>( Path );
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case buffer_TEXT: {
|
case buffer_TEXT: {
|
||||||
@@ -69,7 +73,10 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string
|
|||||||
// destructor
|
// destructor
|
||||||
cParser::~cParser() {
|
cParser::~cParser() {
|
||||||
|
|
||||||
mComments.clear();
|
if( true == mIncFile ) {
|
||||||
|
// wrap up the node group holding content of processed file
|
||||||
|
scene::Groups.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
12
parser.h
12
parser.h
@@ -47,11 +47,6 @@ class cParser //: public std::stringstream
|
|||||||
ignoreToken() {
|
ignoreToken() {
|
||||||
readToken(); };
|
readToken(); };
|
||||||
inline
|
inline
|
||||||
void
|
|
||||||
ignoreTokens(int count) {
|
|
||||||
for( int i = 0; i < count; ++i ) {
|
|
||||||
readToken(); } };
|
|
||||||
inline
|
|
||||||
bool
|
bool
|
||||||
expectToken( std::string const &Value ) {
|
expectToken( std::string const &Value ) {
|
||||||
return readToken() == Value; };
|
return readToken() == Value; };
|
||||||
@@ -97,14 +92,17 @@ class cParser //: public std::stringstream
|
|||||||
std::size_t count();
|
std::size_t count();
|
||||||
// members:
|
// members:
|
||||||
bool m_autoclear { true }; // not retrieved tokens are discarded when another read command is issued (legacy behaviour)
|
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::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 mFile; // name of the open file, if any
|
||||||
std::string mPath; // path to open stream, for relative path lookups.
|
std::string mPath; // path to open stream, for relative path lookups.
|
||||||
std::streamoff mSize { 0 }; // size of open stream, for progress report.
|
std::streamoff mSize { 0 }; // size of open stream, for progress report.
|
||||||
std::size_t mLine { 0 }; // currently processed line
|
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;
|
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::shared_ptr<cParser> mIncludeParser; // child class to handle include directives.
|
||||||
std::vector<std::string> parameters; // parameter list for included file.
|
std::vector<std::string> parameters; // parameter list for included file.
|
||||||
std::deque<std::string> tokens;
|
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 "stdafx.h"
|
||||||
#include "sceneeditor.h"
|
#include "sceneeditor.h"
|
||||||
|
#include "scenenodegroups.h"
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "application.h"
|
#include "application.h"
|
||||||
@@ -22,20 +23,26 @@ namespace scene {
|
|||||||
void
|
void
|
||||||
basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) {
|
basic_editor::translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground ) {
|
||||||
|
|
||||||
auto *node { Node }; // placeholder for operations on multiple nodes
|
auto const initiallocation { Node->location() };
|
||||||
|
auto targetlocation { Location };
|
||||||
auto location { Location };
|
|
||||||
if( false == Snaptoground ) {
|
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 ) ) {
|
if( Node->group() == null_handle ) {
|
||||||
translate_instance( static_cast<TAnimModel *>( node ), location );
|
translate_node( Node, Node->location() + translation );
|
||||||
}
|
}
|
||||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
else {
|
||||||
translate_memorycell( static_cast<TMemCell *>( node ), location );
|
// 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
|
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
|
// NOTE: offset scaling is calculated early so the same multiplier can be applied to potential whole group
|
||||||
auto location { Node->location() };
|
auto location { Node->location() };
|
||||||
auto const distance { glm::length( location - glm::dvec3{ Global.pCamera.Pos } ) };
|
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( Node->group() == null_handle ) {
|
||||||
|
translate_node( Node, offset );
|
||||||
if( typeid( *node ) == typeid( TAnimModel ) ) {
|
|
||||||
translate_instance( static_cast<TAnimModel *>( node ), offset );
|
|
||||||
}
|
}
|
||||||
else if( typeid( *node ) == typeid( TMemCell ) ) {
|
else {
|
||||||
translate_memorycell( static_cast<TMemCell *>( node ), offset );
|
// 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
|
void
|
||||||
basic_editor::rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization ) {
|
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 ) ) {
|
// quantize resulting angle if requested and type of the node allows it
|
||||||
rotate_instance( static_cast<TAnimModel *>( node ), Angle, Quantization );
|
// 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
|
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
|
if( typeid( *Node ) == typeid( TAnimModel ) ) {
|
||||||
glm::vec3 angle = glm::dvec3 { Instance->Angles() };
|
rotate_instance( static_cast<TAnimModel *>( Node ), Angle );
|
||||||
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 );
|
|
||||||
}
|
}
|
||||||
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
|
} // scene
|
||||||
|
|||||||
@@ -36,6 +36,15 @@ public:
|
|||||||
translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground );
|
translate( scene::basic_node *Node, glm::dvec3 const &Location, bool const Snaptoground );
|
||||||
void
|
void
|
||||||
translate( scene::basic_node *Node, float const Offset );
|
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
|
void
|
||||||
translate_instance( TAnimModel *Instance, glm::dvec3 const &Location );
|
translate_instance( TAnimModel *Instance, glm::dvec3 const &Location );
|
||||||
void
|
void
|
||||||
@@ -45,9 +54,9 @@ public:
|
|||||||
void
|
void
|
||||||
translate_memorycell( TMemCell *Memorycell, float const Offset );
|
translate_memorycell( TMemCell *Memorycell, float const Offset );
|
||||||
void
|
void
|
||||||
rotate( scene::basic_node *Node, glm::vec3 const &Angle, float const Quantization );
|
rotate_node( scene::basic_node *Node, glm::vec3 const &Angle );
|
||||||
void
|
void
|
||||||
rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle, float const Quantization );
|
rotate_instance( TAnimModel *Instance, glm::vec3 const &Angle );
|
||||||
};
|
};
|
||||||
|
|
||||||
} // scene
|
} // scene
|
||||||
|
|||||||
19
scenenode.h
19
scenenode.h
@@ -64,6 +64,8 @@ struct bounding_area {
|
|||||||
deserialize( std::istream &Input );
|
deserialize( std::istream &Input );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using group_handle = std::size_t;
|
||||||
|
|
||||||
struct node_data {
|
struct node_data {
|
||||||
|
|
||||||
double range_min { 0.0 };
|
double range_min { 0.0 };
|
||||||
@@ -330,9 +332,14 @@ public:
|
|||||||
visible( bool const Visible );
|
visible( bool const Visible );
|
||||||
bool
|
bool
|
||||||
visible() const;
|
visible() const;
|
||||||
|
void
|
||||||
|
group( scene::group_handle Group );
|
||||||
|
scene::group_handle
|
||||||
|
group() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// members
|
// members
|
||||||
|
scene::group_handle m_group { null_handle }; // group this node belongs to, if any
|
||||||
scene::bounding_area m_area;
|
scene::bounding_area m_area;
|
||||||
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
double m_rangesquaredmin { 0.0 }; // visibility range, min
|
||||||
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
double m_rangesquaredmax { 0.0 }; // visibility range, max
|
||||||
@@ -381,6 +388,18 @@ basic_node::visible() const {
|
|||||||
return m_visible;
|
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
|
} // 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 "globals.h"
|
||||||
#include "simulation.h"
|
#include "simulation.h"
|
||||||
#include "simulationtime.h"
|
#include "simulationtime.h"
|
||||||
|
#include "scenenodegroups.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "dynobj.h"
|
#include "dynobj.h"
|
||||||
@@ -304,6 +305,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
|||||||
delete pathnode;
|
delete pathnode;
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
scene::Groups.register_node( path, scene::Groups.handle() );
|
||||||
simulation::Region->insert_and_register( path );
|
simulation::Region->insert_and_register( path );
|
||||||
}
|
}
|
||||||
else if( nodedata.type == "traction" ) {
|
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 ) ) {
|
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 ) + ")" );
|
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 );
|
simulation::Region->insert_and_register( traction );
|
||||||
}
|
}
|
||||||
else if( nodedata.type == "tractionpowersource" ) {
|
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 ) ) {
|
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 ) + ")" );
|
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 );
|
simulation::Region->insert( instance );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,6 +421,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
|||||||
if( false == simulation::Memory.insert( memorycell ) ) {
|
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 ) + ")" );
|
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 );
|
simulation::Region->insert( memorycell );
|
||||||
}
|
}
|
||||||
else if( nodedata.type == "eventlauncher" ) {
|
else if( nodedata.type == "eventlauncher" ) {
|
||||||
@@ -431,6 +436,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
|||||||
simulation::Events.queue( eventlauncher );
|
simulation::Events.queue( eventlauncher );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
scene::Groups.register_node( eventlauncher, scene::Groups.handle() );
|
||||||
simulation::Region->insert( eventlauncher );
|
simulation::Region->insert( eventlauncher );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user