diff --git a/include/ignition/gazebo/Server.hh b/include/ignition/gazebo/Server.hh index ff8edae5b6..588dfab55b 100644 --- a/include/ignition/gazebo/Server.hh +++ b/include/ignition/gazebo/Server.hh @@ -116,6 +116,8 @@ namespace ignition /// \brief Destructor public: ~Server(); + public: EntityComponentManager &GetEntityComponentManager(); + /// \brief Set the update period. The update period is the wall-clock time /// between ECS updates. /// Note that this is different from the simulation update rate. ECS diff --git a/include/ignition/gazebo/ServerConfig.hh b/include/ignition/gazebo/ServerConfig.hh index 199ccdee35..0acc13ad06 100644 --- a/include/ignition/gazebo/ServerConfig.hh +++ b/include/ignition/gazebo/ServerConfig.hh @@ -175,6 +175,16 @@ namespace ignition /// \return The full contents of the SDF string, or empty string. public: std::string SdfString() const; + /// \brief Set if the server and GUI should run in the same process. + /// \param[in] _sameProcessAsGUI True if the server and GUI will run in + /// the same process, False otherwise + public: void SetSameProcessAsGUI(const bool &_sameProcessAsGUI); + + /// \brief Get if the server and GUI are running in the same process + /// \return True if the server and GUI will run in + /// the same process, False otherwise + public: bool SameProcessAsGUI() const; + /// \brief Set the update rate in Hertz. Value <=0 are ignored. /// \param[in] _hz The desired update rate of the server in Hertz. public: void SetUpdateRate(const double &_hz); @@ -426,7 +436,7 @@ namespace ignition /// \return A list of plugins to load, based on above ordering std::list IGNITION_GAZEBO_VISIBLE - loadPluginInfo(bool _isPlayback = false); + loadPluginInfo(bool _isPlayback = false, bool _sameProcessAsGUI = false); } } } diff --git a/include/ignition/gazebo/gui/Gui.hh b/include/ignition/gazebo/gui/Gui.hh index e23f99cfea..e5e387bd52 100644 --- a/include/ignition/gazebo/gui/Gui.hh +++ b/include/ignition/gazebo/gui/Gui.hh @@ -22,6 +22,7 @@ #include #include "ignition/gazebo/config.hh" +#include "ignition/gazebo/EntityComponentManager.hh" #include "ignition/gazebo/gui/Export.hh" namespace ignition @@ -42,7 +43,9 @@ namespace gui /// \param[in] _guiConfig The GUI configuration file. If nullptr, the default /// configuration from IGN_HOMEDIR/.ignition/gazebo/gui.config will be used. IGNITION_GAZEBO_GUI_VISIBLE int runGui(int &_argc, char **_argv, - const char *_guiConfig); + const char *_guiConfig, + EntityComponentManager &_ecm, + bool sameProcess); /// \brief Create a Gazebo GUI application /// \param[in] _argc Number of command line arguments (Used when running @@ -63,6 +66,8 @@ namespace gui IGNITION_GAZEBO_GUI_VISIBLE std::unique_ptr createGui( int &_argc, char **_argv, const char *_guiConfig, + EntityComponentManager &_ecm, + bool sameProcess, const char *_defaultGuiConfig = nullptr, bool _loadPluginsFromSdf = true); } // namespace gui diff --git a/include/ignition/gazebo/gui/GuiRunner.hh b/include/ignition/gazebo/gui/GuiRunner.hh index e64b4e83fb..3a91ecc5e2 100644 --- a/include/ignition/gazebo/gui/GuiRunner.hh +++ b/include/ignition/gazebo/gui/GuiRunner.hh @@ -26,6 +26,7 @@ #include #include "ignition/gazebo/config.hh" +#include "ignition/gazebo/EntityComponentManager.hh" #include "ignition/gazebo/gui/Export.hh" namespace ignition @@ -45,7 +46,8 @@ class IGNITION_GAZEBO_GUI_VISIBLE GuiRunner : public QObject /// \param[in] _worldName World name. /// \todo Move to src/gui on v6. public: explicit IGN_DEPRECATED(5.0) GuiRunner( - const std::string &_worldName); + const std::string &_worldName, EntityComponentManager &_ecm, + bool sameProcess); /// \brief Destructor public: ~GuiRunner() override; diff --git a/include/ignition/gazebo/rendering/RenderUtil.hh b/include/ignition/gazebo/rendering/RenderUtil.hh index 8f21ff3625..618d99e1e9 100644 --- a/include/ignition/gazebo/rendering/RenderUtil.hh +++ b/include/ignition/gazebo/rendering/RenderUtil.hh @@ -44,7 +44,7 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { class IGNITION_GAZEBO_RENDERING_VISIBLE RenderUtil { /// \brief Constructor - public: explicit RenderUtil(); + public: explicit RenderUtil(bool updateNewEntities); /// \brief Destructor public: ~RenderUtil(); diff --git a/src/Server.cc b/src/Server.cc index aee4486823..f7329e6f9d 100644 --- a/src/Server.cc +++ b/src/Server.cc @@ -206,6 +206,14 @@ Server::Server(const ServerConfig &_config) ///////////////////////////////////////////////// Server::~Server() = default; +EntityComponentManager &Server::GetEntityComponentManager() +{ + for (std::unique_ptr &runner : this->dataPtr->simRunners) + { + return runner->EntityCompMgr(); + } +} + ///////////////////////////////////////////////// bool Server::Run(const bool _blocking, const uint64_t _iterations, const bool _paused) diff --git a/src/ServerConfig.cc b/src/ServerConfig.cc index 8c051d1914..20e7ae6fe7 100644 --- a/src/ServerConfig.cc +++ b/src/ServerConfig.cc @@ -236,7 +236,8 @@ class ignition::gazebo::ServerConfigPrivate networkRole(_cfg->networkRole), networkSecondaries(_cfg->networkSecondaries), seed(_cfg->seed), - logRecordTopics(_cfg->logRecordTopics) { } + logRecordTopics(_cfg->logRecordTopics), + sameProcessAsGUI(_cfg->sameProcessAsGUI) { } // \brief The SDF file that the server should load public: std::string sdfFile = ""; @@ -301,6 +302,10 @@ class ignition::gazebo::ServerConfigPrivate /// \brief Topics to record. public: std::vector logRecordTopics; + + /// \brief Boolean to define if the server and gui run in the same process + /// True gui and server will run in the same process, False otherwise + public: bool sameProcessAsGUI; }; ////////////////////////////////////////////////// @@ -346,6 +351,18 @@ std::string ServerConfig::SdfString() const return this->dataPtr->sdfString; } +////////////////////////////////////////////////// +void ServerConfig::SetSameProcessAsGUI(const bool &_sameProcessAsGUI) +{ + this->dataPtr->sameProcessAsGUI = _sameProcessAsGUI; +} + +////////////////////////////////////////////////// +bool ServerConfig::SameProcessAsGUI() const +{ + return this->dataPtr->sameProcessAsGUI; +} + ////////////////////////////////////////////////// void ServerConfig::SetUpdateRate(const double &_hz) { @@ -824,7 +841,7 @@ ignition::gazebo::parsePluginsFromString(const std::string &_str) ///////////////////////////////////////////////// std::list -ignition::gazebo::loadPluginInfo(bool _isPlayback) +ignition::gazebo::loadPluginInfo(bool _isPlayback, bool _sameProcessAsGUI) { std::list ret; diff --git a/src/SimulationRunner.cc b/src/SimulationRunner.cc index 1e52182873..b261993cc5 100644 --- a/src/SimulationRunner.cc +++ b/src/SimulationRunner.cc @@ -168,7 +168,8 @@ SimulationRunner::SimulationRunner(const sdf::World *_world, { ignmsg << "No systems loaded from SDF, loading defaults" << std::endl; bool isPlayback = !this->serverConfig.LogPlaybackPath().empty(); - auto plugins = ignition::gazebo::loadPluginInfo(isPlayback); + auto plugins = ignition::gazebo::loadPluginInfo( + isPlayback, this->serverConfig.SameProcessAsGUI()); this->LoadServerPlugins(plugins); } @@ -1172,7 +1173,7 @@ bool SimulationRunner::Paused() const } ///////////////////////////////////////////////// -const EntityComponentManager &SimulationRunner::EntityCompMgr() const +EntityComponentManager &SimulationRunner::EntityCompMgr() { return this->entityCompMgr; } diff --git a/src/SimulationRunner.hh b/src/SimulationRunner.hh index 2c5dda2763..98bf457019 100644 --- a/src/SimulationRunner.hh +++ b/src/SimulationRunner.hh @@ -254,7 +254,7 @@ namespace ignition /// \brief Get the EntityComponentManager /// \return Reference to the entity component manager. - public: const EntityComponentManager &EntityCompMgr() const; + public: EntityComponentManager &EntityCompMgr(); /// \brief Return an entity with the provided name. /// \details If multiple entities with the same name exist, the first diff --git a/src/cmd/cmdgazebo.rb.in b/src/cmd/cmdgazebo.rb.in index 30f783c6eb..069819cd87 100755 --- a/src/cmd/cmdgazebo.rb.in +++ b/src/cmd/cmdgazebo.rb.in @@ -54,6 +54,8 @@ COMMANDS = { 'gazebo' => " which loads all models. It's always true \n"\ " with --network-role. \n"\ "\n"\ + " --same-process Server and Client will run in the same process \n"\ + "\n"\ " --network-role [arg] Participant role used in a distributed \n"\ " simulation environment. Role is one of \n"\ " [primary, secondary]. It implies --levels. \n"\ @@ -219,6 +221,7 @@ class Cmd 'log-compress' => 0, 'playback' => '', 'run' => 0, + 'same-process' => 0, 'server' => 0, 'verbose' => '1', 'gui_config' => '', @@ -261,6 +264,9 @@ class Cmd opts.on('--levels') do options['levels'] = 1 end + opts.on('--same-process') do + options['same-process'] = 1 + end opts.on('--record') do options['record'] = 1 end @@ -436,6 +442,13 @@ has properly set the DYLD_LIBRARY_PATH environment variables." # Import the runGui function Importer.extern 'int runGui(const char *)' + # Import the runCombined function + Importer.extern 'int runCombined(const char *, int, int, float, int, + const char *, int, int, const char *, + int, int, int, const char *, const char *, + const char *, const char *, const char *, + const char *, const char *)' + # If playback is specified, and the user has not specified a # custom gui config, set the gui config to load the playback # gui config @@ -443,10 +456,23 @@ has properly set the DYLD_LIBRARY_PATH environment variables." options['gui_config'] = "_playback_" end + if options['same-process'] == 1 + + ENV['RMT_PORT'] = '1500' + Process.setproctitle('ign gazebo') + Importer.runCombined(parsed, options['iterations'], options['run'], + options['hz'], options['levels'], options['network_role'], + options['network_secondaries'], options['record'], + options['record-path'], options['record-resources'], + options['log-overwrite'], options['log-compress'], + options['playback'], options['physics_engine'], + options['render_engine_server'], options['render_engine_gui'], + options['file'], options['record-topics'].join(':'), + options['gui_config']) + # Neither the -s nor -g options were used, so run both the server # and gui. - if options['server'] == 0 && options['gui'] == 0 - + elsif options['server'] == 0 && options['gui'] == 0 if plugin.end_with? ".dylib" puts "`ign gazebo` currently only works with the -s argument on macOS. See https://github.com/ignitionrobotics/ign-gazebo/issues/44 for more info." diff --git a/src/gui/Gui.cc b/src/gui/Gui.cc index 58056f40cf..9329b22bd0 100644 --- a/src/gui/Gui.cc +++ b/src/gui/Gui.cc @@ -43,8 +43,11 @@ namespace gui ////////////////////////////////////////////////// std::unique_ptr createGui( int &_argc, char **_argv, const char *_guiConfig, + EntityComponentManager &_ecm, bool sameProcess, const char *_defaultGuiConfig, bool _loadPluginsFromSdf) { + auto &sharedEcm = _ecm; + ignition::common::SignalHandler sigHandler; bool sigKilled = false; sigHandler.AddCallback([&](const int /*_sig*/) @@ -177,7 +180,7 @@ std::unique_ptr createGui( # pragma warning(push) # pragma warning(disable: 4996) #endif - auto runner = new ignition::gazebo::GuiRunner(worldsMsg.data(0)); + auto runner = new ignition::gazebo::GuiRunner(worldsMsg.data(0), sharedEcm, sameProcess); #ifndef _WIN32 # pragma GCC diagnostic pop #else @@ -241,7 +244,7 @@ std::unique_ptr createGui( # pragma warning(push) # pragma warning(disable: 4996) #endif - auto runner = new ignition::gazebo::GuiRunner(worldName); + auto runner = new ignition::gazebo::GuiRunner(worldName, sharedEcm, sameProcess); #ifndef _WIN32 # pragma GCC diagnostic pop #else @@ -318,9 +321,12 @@ std::unique_ptr createGui( } ////////////////////////////////////////////////// -int runGui(int &_argc, char **_argv, const char *_guiConfig) +int runGui(int &_argc, char **_argv, const char *_guiConfig, + EntityComponentManager &_ecm, bool sameProcess) { - auto app = gazebo::gui::createGui(_argc, _argv, _guiConfig); + auto &sharedEcm = _ecm; + auto app = gazebo::gui::createGui(_argc, _argv, _guiConfig, + sharedEcm, sameProcess); if (nullptr != app) { // Run main window. diff --git a/src/gui/GuiRunner.cc b/src/gui/GuiRunner.cc index d06032fa22..dc927da3eb 100644 --- a/src/gui/GuiRunner.cc +++ b/src/gui/GuiRunner.cc @@ -35,11 +35,17 @@ using namespace gazebo; ///////////////////////////////////////////////// class ignition::gazebo::GuiRunner::Implementation { + + public: explicit Implementation(gazebo::EntityComponentManager &_ecm) + : ecm(_ecm){} + /// \brief Update the plugins. public: void UpdatePlugins(); /// \brief Entity-component manager. - public: gazebo::EntityComponentManager ecm; + public: gazebo::EntityComponentManager &ecm; + + public: bool sameProcess; /// \brief Transport node. public: transport::Node node{}; @@ -61,10 +67,15 @@ class ignition::gazebo::GuiRunner::Implementation }; ///////////////////////////////////////////////// -GuiRunner::GuiRunner(const std::string &_worldName) - : dataPtr(utils::MakeUniqueImpl()) +GuiRunner::GuiRunner(const std::string &_worldName, + EntityComponentManager &_ecm, bool _sameProcess) + : dataPtr(utils::MakeUniqueImpl(_ecm)) { + this->dataPtr->sameProcess = _sameProcess; + this->setProperty("worldName", QString::fromStdString(_worldName)); + this->setProperty("sameProcess", + QString::fromStdString(std::to_string(_sameProcess))); auto win = gui::App()->findChild(); auto winWorldNames = win->property("worldNames").toStringList(); @@ -118,6 +129,9 @@ GuiRunner::~GuiRunner() ///////////////////////////////////////////////// void GuiRunner::RequestState() { + if (this->dataPtr->sameProcess) + return; + // set up service for async state response callback std::string id = std::to_string(gui::App()->applicationPid()); std::string reqSrv = diff --git a/src/gui/plugins/scene3d/Scene3D.cc b/src/gui/plugins/scene3d/Scene3D.cc index 3068321270..909e7e7b82 100644 --- a/src/gui/plugins/scene3d/Scene3D.cc +++ b/src/gui/plugins/scene3d/Scene3D.cc @@ -70,6 +70,9 @@ #include "ignition/gazebo/gui/GuiEvents.hh" #include "ignition/gazebo/rendering/RenderUtil.hh" +#include +#include + /// \brief condition variable for lockstepping video recording /// todo(anyone) avoid using a global condition variable when we support /// multiple viewports in the future. @@ -163,6 +166,11 @@ inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { /// \brief Private data class for IgnRenderer class IgnRendererPrivate { + public: explicit IgnRendererPrivate(bool updateNewModels) + : renderUtil(updateNewModels), sameProcess(updateNewModels){} + + public: bool sameProcess = false; + /// \brief Flag to indicate if mouse event is dirty public: bool mouseDirty = false; @@ -449,8 +457,28 @@ QList RenderWindowItemPrivate::threads; ///////////////////////////////////////////////// IgnRenderer::IgnRenderer() - : dataPtr(new IgnRendererPrivate) { + auto runners = ignition::gui::App()->findChildren(); + if (runners.empty() || runners[0] == nullptr) + { + ignerr << "Internal error: no GuiRunner found." << std::endl; + return; + } + + bool sameProcess = false; + auto sameProcessVariant = runners[0]->property("sameProcess"); + if (!sameProcessVariant.isValid()) + { + ignwarn << "GuiRunner's worldName not set, using[" + << sameProcess << "]" << std::endl; + } + else + { + sameProcess = sameProcessVariant.toBool(); + } + + this->dataPtr = std::make_unique(sameProcess); + this->dataPtr->moveToHelper.initCameraPose = this->cameraPose; // recorder stats topic @@ -509,7 +537,7 @@ void IgnRenderer::Render() this->dataPtr->renderUtil.Update(); // view control - this->HandleMouseEvent(); + // this->HandleMouseEvent(); // Entity selection this->HandleEntitySelection(); @@ -2798,7 +2826,9 @@ void Scene3D::Update(const UpdateInfo &_info, this->dataPtr->cameraPosePub.Publish(poseMsg); } this->dataPtr->renderUtil->UpdateECM(_info, _ecm); + // ignerr << "UpdateFromECM\n"; this->dataPtr->renderUtil->UpdateFromECM(_info, _ecm); + // ignerr << "UpdateFromECM2\n"; // check if video recording is enabled and if we need to lock step // ECM updates with GUI rendering during video recording diff --git a/src/ign.cc b/src/ign.cc index 9faf652e09..67f9d2f746 100644 --- a/src/ign.cc +++ b/src/ign.cc @@ -31,6 +31,7 @@ #include "ignition/gazebo/config.hh" #include "ignition/gazebo/Server.hh" #include "ignition/gazebo/ServerConfig.hh" +#include "SimulationRunner.hh" #include "ignition/gazebo/gui/Gui.hh" @@ -115,18 +116,19 @@ extern "C" const char *findFuelResource( } ////////////////////////////////////////////////// -extern "C" int runServer(const char *_sdfString, - int _iterations, int _run, float _hz, int _levels, const char *_networkRole, +int createServerConfig(ignition::gazebo::ServerConfig &_serverConfig, + const char *_sdfString, + float _hz, int _levels, const char *_networkRole, int _networkSecondaries, int _record, const char *_recordPath, int _recordResources, int _logOverwrite, int _logCompress, const char *_playback, const char *_physicsEngine, const char *_renderEngineServer, const char *_renderEngineGui, - const char *_file, const char *_recordTopics) + const char *_file, const char *_recordTopics, bool _sameProcessAsGUI) { - ignition::gazebo::ServerConfig serverConfig; - // Path for logs - std::string recordPathMod = serverConfig.LogRecordPath(); + std::string recordPathMod = _serverConfig.LogRecordPath(); + + _serverConfig.SetSameProcessAsGUI(_sameProcessAsGUI); // Path for compressed log, used to check for duplicates std::string cmpPath = std::string(recordPathMod); @@ -148,8 +150,8 @@ extern "C" int runServer(const char *_sdfString, return -1; } - serverConfig.SetUseLogRecord(true); - serverConfig.SetLogRecordResources(_recordResources); + _serverConfig.SetUseLogRecord(true); + _serverConfig.SetLogRecordResources(_recordResources); // If a record path is specified if (_recordPath != nullptr && std::strlen(_recordPath) > 0) @@ -261,23 +263,23 @@ extern "C" int runServer(const char *_sdfString, ignmsg << "Recording states to default path [" << recordPathMod << "]" << std::endl; } - serverConfig.SetLogRecordPath(recordPathMod); + _serverConfig.SetLogRecordPath(recordPathMod); std::vector topics = ignition::common::split( _recordTopics, ":"); for (const std::string &topic : topics) { - serverConfig.AddLogRecordTopic(topic); + _serverConfig.AddLogRecordTopic(topic); } } else { - ignLogInit(serverConfig.LogRecordPath(), "server_console.log"); + ignLogInit(_serverConfig.LogRecordPath(), "server_console.log"); } if (_logCompress > 0) { - serverConfig.SetLogRecordCompressPath(cmpPath); + _serverConfig.SetLogRecordCompressPath(cmpPath); } ignmsg << "Ignition Gazebo Server v" << IGNITION_GAZEBO_VERSION_FULL @@ -286,31 +288,31 @@ extern "C" int runServer(const char *_sdfString, // Set the SDF string to user if (_sdfString != nullptr && std::strlen(_sdfString) > 0) { - if (!serverConfig.SetSdfString(_sdfString)) + if (!_serverConfig.SetSdfString(_sdfString)) { ignerr << "Failed to set SDF string [" << _sdfString << "]" << std::endl; return -1; } } - serverConfig.SetSdfFile(_file); + _serverConfig.SetSdfFile(_file); // Set the update rate. if (_hz > 0.0) - serverConfig.SetUpdateRate(_hz); + _serverConfig.SetUpdateRate(_hz); // Set whether levels should be used. if (_levels > 0) { ignmsg << "Using the level system\n"; - serverConfig.SetUseLevels(true); + _serverConfig.SetUseLevels(true); } if (_networkRole && std::strlen(_networkRole) > 0) { ignmsg << "Using the distributed simulation and levels systems\n"; - serverConfig.SetNetworkRole(_networkRole); - serverConfig.SetNetworkSecondaries(_networkSecondaries); - serverConfig.SetUseLevels(true); + _serverConfig.SetNetworkRole(_networkRole); + _serverConfig.SetNetworkSecondaries(_networkSecondaries); + _serverConfig.SetUseLevels(true); } if (_playback != nullptr && std::strlen(_playback) > 0) @@ -324,36 +326,104 @@ extern "C" int runServer(const char *_sdfString, else { ignmsg << "Playing back states" << _playback << std::endl; - serverConfig.SetLogPlaybackPath(ignition::common::absPath( + _serverConfig.SetLogPlaybackPath(ignition::common::absPath( std::string(_playback))); } } if (_physicsEngine != nullptr && std::strlen(_physicsEngine) > 0) { - serverConfig.SetPhysicsEngine(_physicsEngine); + _serverConfig.SetPhysicsEngine(_physicsEngine); } if (_renderEngineServer != nullptr && std::strlen(_renderEngineServer) > 0) { - serverConfig.SetRenderEngineServer(_renderEngineServer); + _serverConfig.SetRenderEngineServer(_renderEngineServer); } if (_renderEngineGui != nullptr && std::strlen(_renderEngineGui) > 0) { - serverConfig.SetRenderEngineGui(_renderEngineGui); + _serverConfig.SetRenderEngineGui(_renderEngineGui); } + return 0; +} + +////////////////////////////////////////////////// +extern "C" IGNITION_GAZEBO_VISIBLE int runServer(const char *_sdfString, + int _iterations, int _run, float _hz, int _levels, const char *_networkRole, + int _networkSecondaries, int _record, const char *_recordPath, + int _recordResources, int _logOverwrite, int _logCompress, + const char *_playback, const char *_physicsEngine, + const char *_renderEngineServer, const char *_renderEngineGui, + const char *_file, const char *_recordTopics) +{ // Create the Gazebo server - ignition::gazebo::Server server(serverConfig); + ignition::gazebo::ServerConfig serverConfig; - // Run the server - server.Run(true, _iterations, _run == 0); + if (createServerConfig(serverConfig, + _sdfString, _hz, _levels, _networkRole, + _networkSecondaries, _record, _recordPath, + _recordResources, _logOverwrite, _logCompress, + _playback, _physicsEngine, _renderEngineServer, + _renderEngineGui, _file, _recordTopics, false) == 0) + { + ignition::gazebo::Server server(serverConfig); + // Run the server + server.Run(true, _iterations, _run == 0); + igndbg << "Shutting down ign-gazebo-server" << std::endl; + return 0; + } igndbg << "Shutting down ign-gazebo-server" << std::endl; return 0; } +////////////////////////////////////////////////// +extern "C" IGNITION_GAZEBO_VISIBLE int runCombined(const char *_sdfString, + int _iterations, int _run, float _hz, int _levels, const char *_networkRole, + int _networkSecondaries, int _record, const char *_recordPath, + int _recordResources, int _logOverwrite, int _logCompress, + const char *_playback, const char *_physicsEngine, + const char *_renderEngineServer, const char *_renderEngineGui, + const char *_file, const char *_recordTopics, const char *_guiConfig) +{ + ignition::gazebo::ServerConfig serverConfig; + + if (createServerConfig(serverConfig, + _sdfString, _hz, _levels, _networkRole, + _networkSecondaries, _record, _recordPath, + _recordResources, _logOverwrite, _logCompress, + _playback, _physicsEngine, _renderEngineServer, + _renderEngineGui, _file, _recordTopics, true) == 0) + { + // Create the Gazebo server + ignition::gazebo::Server server(serverConfig); + + // Run the server + server.Run(false, _iterations, _run == 0); + + auto &sharedEcm = server.GetEntityComponentManager(); + + // argc and argv are going to be passed to a QApplication. The Qt + // documentation has a warning about these: + // "Warning: The data referred to by argc and argv must stay valid for the + // entire lifetime of the QApplication object. In addition, argc must be + // greater than zero and argv must contain at least one valid character + // string." + int argc = 1; + // Converting a string literal to char * is forbidden as of C++11. It can only + // be converted to a const char *. The const cast is here to prevent a warning + // since we do need to pass a char* to runGui + char *argv = const_cast("ign-gazebo-gui"); + return ignition::gazebo::gui::runGui(argc, &argv, _guiConfig, sharedEcm, true); + } + + ignerr << "Unable to create server config\n"; + + return -1; +} + ////////////////////////////////////////////////// extern "C" int runGui(const char *_guiConfig) { @@ -368,5 +438,6 @@ extern "C" int runGui(const char *_guiConfig) // be converted to a const char *. The const cast is here to prevent a warning // since we do need to pass a char* to runGui char *argv = const_cast("ign-gazebo-gui"); - return ignition::gazebo::gui::runGui(argc, &argv, _guiConfig); + ignition::gazebo::v5::EntityComponentManager guiEcm; + return ignition::gazebo::gui::runGui(argc, &argv, _guiConfig, guiEcm, false); } diff --git a/src/ign.hh b/src/ign.hh index 3b7cd3c5e4..2d807615d2 100644 --- a/src/ign.hh +++ b/src/ign.hh @@ -76,4 +76,35 @@ extern "C" int runGui(const char *_guiConfig); extern "C" const char *findFuelResource( char *_pathToResource); +/// \brief External hook to run simulation server and GUI. +/// \param[in] _sdfString SDF file to run, as a string. +/// \param[in] _iterations --iterations option +/// \param[in] _run -r option +/// \param[in] _hz -z option +/// \param[in] _levels --levels option +/// \param[in] _networkRole --network-role option +/// \param[in] _networkSecondaries --network-secondaries option +/// \param[in] _record --record option +/// \param[in] _recordPath --record-path option +/// \param[in] _recordResources --record-resources option +/// \param[in] _logOverwrite --log-overwrite option +/// \param[in] _logCompress --log-compress option +/// \param[in] _playback --playback option +/// \param[in] _physicsEngine --physics-engine option +/// \param[in] _renderEngineServer --render-engine-server option +/// \param[in] _renderEngineGui --render-engine-gui option +/// \param[in] _file Path to file being loaded +/// \param[in] _recordTopics Colon separated list of topics to record. Leave +/// null to record the default topics. +/// \param[in] _guiConfig Path to Ignition GUI configuration file. +/// \return 0 if successful, 1 if not. +extern "C" IGNITION_GAZEBO_VISIBLE int runCombined(const char *_sdfString, + int _iterations, int _run, float _hz, int _levels, const char *_networkRole, + int _networkSecondaries, int _record, const char *_recordPath, + int _recordResources, int _logOverwrite, int _logCompress, + const char *_playback, const char *_physicsEngine, + const char *_renderEngineServer, const char *_renderEngineGui, + const char *_file, const char *_recordTopics, const char *_guiConfig); + + #endif diff --git a/src/rendering/RenderUtil.cc b/src/rendering/RenderUtil.cc index 382a48ae86..15683d2c54 100644 --- a/src/rendering/RenderUtil.cc +++ b/src/rendering/RenderUtil.cc @@ -327,13 +327,16 @@ class ignition::gazebo::RenderUtilPrivate /// \brief A map of entity id to thermal camera sensor configuration /// properties. The elements in the tuple are: /// - public:std::unordered_map> thermalCameraData; + + public: bool sameProcess; }; ////////////////////////////////////////////////// -RenderUtil::RenderUtil() : dataPtr(std::make_unique()) +RenderUtil::RenderUtil(bool _sameProcess) : dataPtr(std::make_unique()) { + this->dataPtr->sameProcess = _sameProcess; } ////////////////////////////////////////////////// @@ -625,6 +628,8 @@ void RenderUtil::Update() // create new entities { IGN_PROFILE("RenderUtil::Update Create"); + // std::cerr << "newModels size " << newModels.size() << '\n'; + for (const auto &model : newModels) { uint64_t iteration = std::get<3>(model); @@ -1151,9 +1156,18 @@ void RenderUtilPrivate::CreateRenderingEntities( sdf::Model model; model.SetName(_name->Data()); model.SetRawPose(_pose->Data()); - this->newModels.push_back( - std::make_tuple(_entity, model, _parent->Data(), - _info.iterations)); + auto tupleTemp = std::make_tuple(_entity, model, _parent->Data(), + _info.iterations); + bool found = false; + for (auto & data: this->newModels) + { + if (std::get<0>(data) == std::get<0>(tupleTemp)) + { + found = true; + } + } + if (!found) + this->newModels.push_back(tupleTemp); return true; }); @@ -1379,9 +1393,18 @@ void RenderUtilPrivate::CreateRenderingEntities( sdf::Model model; model.SetName(_name->Data()); model.SetRawPose(_pose->Data()); - this->newModels.push_back( - std::make_tuple(_entity, model, _parent->Data(), - _info.iterations)); + auto tupleTemp = std::make_tuple(_entity, model, _parent->Data(), + _info.iterations); + bool found = false; + for (auto & data: this->newModels) + { + if (std::get<0>(data) == std::get<0>(tupleTemp)) + { + found = true; + } + } + if (!found) + this->newModels.push_back(tupleTemp); return true; }); @@ -1824,9 +1847,12 @@ void RenderUtilPrivate::RemoveRenderingEntities( }); } +static std::mutex mutexInit; ///////////////////////////////////////////////// void RenderUtil::Init() { + std::lock_guard lock(mutexInit); + ignition::common::SystemPaths pluginPath; pluginPath.SetPluginPathEnv(kRenderPluginPathEnv); rendering::setPluginPaths(pluginPath.PluginPaths()); diff --git a/src/systems/sensors/Sensors.cc b/src/systems/sensors/Sensors.cc index a20b5c3280..f54cc9cf45 100644 --- a/src/systems/sensors/Sensors.cc +++ b/src/systems/sensors/Sensors.cc @@ -57,6 +57,9 @@ using namespace systems; // Private data class. class ignition::gazebo::systems::SensorsPrivate { + public: explicit SensorsPrivate() + : renderUtil(false){} + /// \brief Sensor manager object. This manages the lifecycle of the /// instantiated sensors. public: sensors::Manager sensorManager;