diff --git a/resource_retriever_msgs/CMakeLists.txt b/resource_retriever_msgs/CMakeLists.txt new file mode 100644 index 000000000..80fad1ad1 --- /dev/null +++ b/resource_retriever_msgs/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.8) +project(resource_retriever_msgs) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "srv/GetResource.srv" +) + +ament_export_dependencies(rosidl_default_runtime) +ament_package() diff --git a/resource_retriever_msgs/package.xml b/resource_retriever_msgs/package.xml new file mode 100644 index 000000000..e3bc78e79 --- /dev/null +++ b/resource_retriever_msgs/package.xml @@ -0,0 +1,21 @@ + + + + resource_retriever_msgs + 0.0.0 + TODO: Package description + eloy + Apache-2.0 + + ament_cmake + + rosidl_default_generators + + rosidl_default_runtime + + rosidl_interface_packages + + + ament_cmake + + diff --git a/resource_retriever_msgs/srv/GetResource.srv b/resource_retriever_msgs/srv/GetResource.srv new file mode 100644 index 000000000..a9fdb9dcf --- /dev/null +++ b/resource_retriever_msgs/srv/GetResource.srv @@ -0,0 +1,5 @@ +string path +--- +string path +int32 status_code +uint8[] body diff --git a/rviz_common/src/rviz_common/load_resource.cpp b/rviz_common/src/rviz_common/load_resource.cpp index b2b22da74..ed19c95c8 100644 --- a/rviz_common/src/rviz_common/load_resource.cpp +++ b/rviz_common/src/rviz_common/load_resource.cpp @@ -46,18 +46,11 @@ namespace rviz_common { -resource_retriever::MemoryResource getResource(const std::string & resource_path) +resource_retriever::MemoryResourcePtr getResource(const std::string & resource_path) { + printf("rviz_common::getResource: %s\n", resource_path.c_str()); resource_retriever::Retriever retriever; - resource_retriever::MemoryResource res; - try { - res = retriever.get(resource_path); - } catch (resource_retriever::Exception & e) { - RVIZ_COMMON_LOG_DEBUG(e.what()); - return resource_retriever::MemoryResource(); - } - - return res; + return retriever.get(resource_path); } QPixmap loadPixmap(QString url, bool fill_cache) @@ -72,8 +65,8 @@ QPixmap loadPixmap(QString url, bool fill_cache) RVIZ_COMMON_LOG_DEBUG("Load pixmap at " + url.toStdString()); auto image = getResource(url.toStdString()); - if (image.size != 0) { - if (!pixmap.loadFromData(image.data.get(), static_cast(image.size))) { + if (image!= nullptr && !image->data.empty()) { + if (!pixmap.loadFromData(image->data.data(), static_cast(image->data.size()))) { RVIZ_COMMON_LOG_ERROR("Could not load pixmap " + url.toStdString()); } } diff --git a/rviz_default_plugins/CMakeLists.txt b/rviz_default_plugins/CMakeLists.txt index 1bdc96b17..27ec5181c 100644 --- a/rviz_default_plugins/CMakeLists.txt +++ b/rviz_default_plugins/CMakeLists.txt @@ -73,6 +73,7 @@ find_package(pluginlib REQUIRED) find_package(point_cloud_transport REQUIRED) find_package(rclcpp REQUIRED) find_package(resource_retriever REQUIRED) +find_package(resource_retriever_msgs REQUIRED) find_package(sensor_msgs REQUIRED) find_package(tf2 REQUIRED) find_package(tf2_geometry_msgs REQUIRED) @@ -262,11 +263,12 @@ target_link_libraries(rviz_default_plugins PUBLIC tf2_ros::tf2_ros urdf::urdf ${visualization_msgs_TARGETS} + resource_retriever::resource_retriever + ${resource_retriever_msgs_TARGETS} ) target_link_libraries(rviz_default_plugins PRIVATE gz-math::core - resource_retriever::resource_retriever ) # Causes the visibility macros to use dllexport rather than dllimport, diff --git a/rviz_default_plugins/include/rviz_default_plugins/displays/marker/marker_common.hpp b/rviz_default_plugins/include/rviz_default_plugins/displays/marker/marker_common.hpp index 42acdcef2..569b128db 100644 --- a/rviz_default_plugins/include/rviz_default_plugins/displays/marker/marker_common.hpp +++ b/rviz_default_plugins/include/rviz_default_plugins/displays/marker/marker_common.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,8 @@ class RVIZ_DEFAULT_PLUGINS_PUBLIC MarkerCommon void setMarkerStatus(MarkerID id, StatusLevel level, const std::string & text); void deleteMarkerStatus(MarkerID id); + resource_retriever::Retriever * getResourceRetriever(); + private: /** @brief Delete all the markers within the given namespace. */ void deleteMarkersInNamespace(const std::string & ns); @@ -173,6 +176,8 @@ class RVIZ_DEFAULT_PLUGINS_PUBLIC MarkerCommon rviz_common::DisplayContext * context_; Ogre::SceneNode * scene_node_; + resource_retriever::Retriever retriever_; + friend class MarkerNamespace; }; diff --git a/rviz_default_plugins/include/rviz_default_plugins/robot/robot_link.hpp b/rviz_default_plugins/include/rviz_default_plugins/robot/robot_link.hpp index 7bb7ce1fc..0cae06025 100644 --- a/rviz_default_plugins/include/rviz_default_plugins/robot/robot_link.hpp +++ b/rviz_default_plugins/include/rviz_default_plugins/robot/robot_link.hpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -234,6 +235,8 @@ private Q_SLOTS: Ogre::SceneManager * scene_manager_; rviz_common::DisplayContext * context_; + mutable resource_retriever::Retriever retriever_; + std::string parent_joint_name_; std::vector child_joint_names_; diff --git a/rviz_default_plugins/package.xml b/rviz_default_plugins/package.xml index e4c2d7ea2..99513435f 100644 --- a/rviz_default_plugins/package.xml +++ b/rviz_default_plugins/package.xml @@ -48,6 +48,7 @@ point_cloud_transport rclcpp resource_retriever + resource_retriever_msgs rviz_common rviz_rendering tf2 diff --git a/rviz_default_plugins/src/rviz_default_plugins/displays/marker/marker_common.cpp b/rviz_default_plugins/src/rviz_default_plugins/displays/marker/marker_common.cpp index a97e5bba5..244d440c3 100644 --- a/rviz_default_plugins/src/rviz_default_plugins/displays/marker/marker_common.cpp +++ b/rviz_default_plugins/src/rviz_default_plugins/displays/marker/marker_common.cpp @@ -32,6 +32,12 @@ #include "rviz_default_plugins/displays/marker/marker_common.hpp" #include +#include +#include +#include +#include +#include +#include #include #include #include @@ -47,6 +53,87 @@ #include "rviz_default_plugins/displays/marker/markers/marker_factory.hpp" +#include + +class RosRetriever: public resource_retriever::plugins::RetrieverPlugin +{ + using GetResource = resource_retriever_msgs::srv::GetResource; + +public: + explicit RosRetriever(rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr ros_iface): + ros_iface_(std::move(ros_iface)) + { + auto iface = ros_iface_.lock(); + auto raw_node = iface->get_raw_node(); + callback_group_ = raw_node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive, false); + this->client_ = raw_node->create_client("/get_resource", rclcpp::ServicesQoS(), callback_group_); + } + + ~RosRetriever() override = default; + + std::string name() override + { + return "rviz_common::RosRetriever"; + } + + bool can_handle(const std::string & url) override + { + return !url.empty(); + } + + resource_retriever::MemoryResourcePtr get(const std::string & url) override + { + auto it = cached_resources_.find(url); + if (it != cached_resources_.end()) + { + RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "[Resource Cached]: %s", url.c_str()); + return it->second; + } + + auto node = ros_iface_.lock(); + if (nullptr == node) + { + RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Could not acquire node lock"); + return nullptr; + } + + auto raw_node = node->get_raw_node(); + if (nullptr == node->get_raw_node()) + { + RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Could not acquire raw node"); + return nullptr; + } + + auto req = std::make_shared(); + req->path = url; + RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sending request"); + auto result = this->client_->async_send_request(req); + + auto exec = rclcpp::executors::SingleThreadedExecutor(); + exec.add_callback_group(callback_group_, raw_node->get_node_base_interface()); + exec.spin_until_future_complete(result); + RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Waiting done"); + + auto res = result.get(); + RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Result: %s", res->path.c_str()); + + if (res->status_code == 0) + { + RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "[Retrieved resource]: %s", url.c_str()); + cached_resources_.insert({url, std::make_shared(url, res->path, res->body)}); + return cached_resources_[url]; + } + + return nullptr; + } + +private: + rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr ros_iface_; + rclcpp::CallbackGroup::SharedPtr callback_group_; + rclcpp::Client::SharedPtr client_; + std::unordered_map cached_resources_; +}; + namespace rviz_default_plugins { namespace displays @@ -58,6 +145,7 @@ MarkerCommon::MarkerCommon(rviz_common::Display * display) namespaces_category_ = new rviz_common::properties::Property( "Namespaces", QVariant(), "", display_); marker_factory_ = std::make_unique(); + } MarkerCommon::~MarkerCommon() @@ -70,6 +158,14 @@ void MarkerCommon::initialize(rviz_common::DisplayContext * context, Ogre::Scene context_ = context; scene_node_ = scene_node; + resource_retriever::RetrieverVec plugins; + plugins.push_back(std::make_shared(context_->getRosNodeAbstraction())); + for (const auto & plugin : resource_retriever::default_plugins()) + { + plugins.push_back(plugin); + } + retriever_ = resource_retriever::Retriever(plugins); + namespace_config_enabled_state_.clear(); marker_factory_->initialize(this, context_, scene_node_); @@ -146,6 +242,11 @@ void MarkerCommon::deleteMarkerStatus(MarkerID id) display_->deleteStatusStd(marker_name); } +resource_retriever::Retriever * MarkerCommon::getResourceRetriever() +{ + return &this->retriever_; +} + void MarkerCommon::addMessage(const visualization_msgs::msg::Marker::ConstSharedPtr marker) { std::unique_lock lock(queue_mutex_); diff --git a/rviz_default_plugins/src/rviz_default_plugins/displays/marker/markers/mesh_resource_marker.cpp b/rviz_default_plugins/src/rviz_default_plugins/displays/marker/markers/mesh_resource_marker.cpp index 8f92c7cee..3d1f527a8 100644 --- a/rviz_default_plugins/src/rviz_default_plugins/displays/marker/markers/mesh_resource_marker.cpp +++ b/rviz_default_plugins/src/rviz_default_plugins/displays/marker/markers/mesh_resource_marker.cpp @@ -109,7 +109,7 @@ void MeshResourceMarker::onNewMessage( return; } - if (!rviz_rendering::loadMeshFromResource(new_message->mesh_resource)) { + if (!rviz_rendering::loadMeshFromResource(owner_->getResourceRetriever(), new_message->mesh_resource)) { printMeshLoadingError(new_message); return; } diff --git a/rviz_default_plugins/src/rviz_default_plugins/robot/robot_link.cpp b/rviz_default_plugins/src/rviz_default_plugins/robot/robot_link.cpp index 207960ede..efea21c52 100644 --- a/rviz_default_plugins/src/rviz_default_plugins/robot/robot_link.cpp +++ b/rviz_default_plugins/src/rviz_default_plugins/robot/robot_link.cpp @@ -91,6 +91,36 @@ using rviz_common::properties::Property; using rviz_common::properties::FloatProperty; using rviz_common::properties::QuaternionProperty; using rviz_common::properties::VectorProperty; +class RosRetriever: public resource_retriever::plugins::RetrieverPlugin + +{ +public: + explicit RosRetriever(rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr ros_iface): + ros_iface_(std::move(ros_iface)) + { + } + + ~RosRetriever() override {}; + + std::string name() override + { + return "rviz_common::RosRetriever"; + } + + bool can_handle(const std::string & url) override + { + return true; + } + + resource_retriever::MemoryResourcePtr get(const std::string & url) override + { + printf("Trying to get %s\n", url.c_str()); + return nullptr; + } + +private: + rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr ros_iface_; +}; class RobotLinkSelectionHandler : public rviz_common::interaction::SelectionHandler { @@ -225,6 +255,14 @@ RobotLink::RobotLink( color_material_ = rviz_rendering::MaterialManager::createMaterialWithLighting(color_material_name); + resource_retriever::RetrieverVec plugins; + plugins.push_back(std::make_shared(context_->getRosNodeAbstraction())); + for (const auto & plugin : resource_retriever::default_plugins()) + { + plugins.push_back(plugin); + } + retriever_ = resource_retriever::Retriever(plugins); + // create the ogre objects to display if (visual) { createVisual(link); @@ -672,7 +710,7 @@ Ogre::Entity * RobotLink::createEntityForGeometryElement( const std::string & model_name = mesh.filename; try { - if (rviz_rendering::loadMeshFromResource(model_name) == nullptr) { + if (rviz_rendering::loadMeshFromResource(&retriever_, model_name) == nullptr) { addError("Could not load mesh resource '%s'", model_name.c_str()); } else { entity = scene_manager_->createEntity(entity_name, model_name); @@ -800,16 +838,9 @@ void RobotLink::loadMaterialFromTexture( { std::string filename = visual->material->texture_filename; if (!Ogre::TextureManager::getSingleton().resourceExists(filename, RVIZ_RESOURCE_GROUP)) { - resource_retriever::Retriever retriever; - resource_retriever::MemoryResource res; - try { - res = retriever.get(filename); - } catch (resource_retriever::Exception & e) { - RVIZ_COMMON_LOG_ERROR(e.what()); - } - - if (res.size != 0) { - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); + auto res = retriever_.get(filename); + if (nullptr != res && !res->data.empty()) { + Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(const_cast(res->data.data()), res->data.size())); Ogre::Image image; std::string extension = QFileInfo(QString::fromStdString(filename)).completeSuffix().toStdString(); diff --git a/rviz_default_plugins/test/rviz_default_plugins/robot/robot_test.cpp b/rviz_default_plugins/test/rviz_default_plugins/robot/robot_test.cpp index de0b08be2..325b9046b 100644 --- a/rviz_default_plugins/test/rviz_default_plugins/robot/robot_test.cpp +++ b/rviz_default_plugins/test/rviz_default_plugins/robot/robot_test.cpp @@ -84,8 +84,8 @@ class RobotTestFixture : public Test EXPECT_CALL(*context_, getHandlerManager()).WillRepeatedly(Return(handle_manager_)); resource_retriever::Retriever retriever; - auto file = retriever.get("package://rviz_default_plugins/test_meshes/test.urdf"); - std::string string(reinterpret_cast(file.data.get()), file.size); + auto res = retriever.get("package://rviz_default_plugins/test_meshes/test.urdf"); + std::string string(reinterpret_cast(const_cast(res->data.data())), res->data.size()); urdf_model_.initString(string); parent_ = std::make_shared(); diff --git a/rviz_rendering/include/rviz_rendering/mesh_loader.hpp b/rviz_rendering/include/rviz_rendering/mesh_loader.hpp index c8c3187aa..4026df501 100644 --- a/rviz_rendering/include/rviz_rendering/mesh_loader.hpp +++ b/rviz_rendering/include/rviz_rendering/mesh_loader.hpp @@ -37,11 +37,13 @@ #include "rviz_rendering/visibility_control.hpp" +#include "resource_retriever/retriever.hpp" + namespace rviz_rendering { RVIZ_RENDERING_PUBLIC -Ogre::MeshPtr loadMeshFromResource(const std::string & resource_path); - +Ogre::MeshPtr loadMeshFromResource(resource_retriever::Retriever * retriever, + const std::string & resource_uri); } // namespace rviz_rendering #endif // RVIZ_RENDERING__MESH_LOADER_HPP_ diff --git a/rviz_rendering/src/rviz_rendering/mesh_loader.cpp b/rviz_rendering/src/rviz_rendering/mesh_loader.cpp index 4c8658eb0..2b29dcc4b 100644 --- a/rviz_rendering/src/rviz_rendering/mesh_loader.cpp +++ b/rviz_rendering/src/rviz_rendering/mesh_loader.cpp @@ -31,6 +31,8 @@ #include "rviz_rendering/mesh_loader.hpp" +#include +#include #include #include "OgreHardwareBufferManager.h" @@ -71,55 +73,46 @@ namespace rviz_rendering { -resource_retriever::MemoryResource getResource(const std::string & resource_path) +Ogre::MeshPtr loadMeshFromResource(resource_retriever::Retriever * retriever, + const std::string & resource_uri) { - resource_retriever::Retriever retriever; - resource_retriever::MemoryResource res; - try { - res = retriever.get(resource_path); - } catch (resource_retriever::Exception & e) { - RVIZ_RENDERING_LOG_ERROR(e.what()); - return resource_retriever::MemoryResource(); + printf("loadMeshFromResource: %s\n", resource_uri.c_str()); + // Early exit with empty retriever + if (nullptr == retriever) { + return nullptr; } - return res; -} - -Ogre::MeshPtr loadMeshFromResource(const std::string & resource_path) -{ - if (Ogre::MeshManager::getSingleton().resourceExists(resource_path, ROS_PACKAGE_NAME)) { - return Ogre::MeshManager::getSingleton().getByName(resource_path, ROS_PACKAGE_NAME); - } else { - QFileInfo model_path(QString::fromStdString(resource_path)); - std::string ext = model_path.completeSuffix().toStdString(); - if (ext == "mesh" || ext == "MESH") { - auto res = getResource(resource_path); - - if (res.size == 0) { - return Ogre::MeshPtr(); - } - - Ogre::MeshSerializer ser; - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); - Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual( - resource_path, ROS_PACKAGE_NAME); - ser.importMesh(stream, mesh.get()); - stream->close(); - - return mesh; - } else { - AssimpLoader assimp_loader; + // Check for cached resources + if (Ogre::MeshManager::getSingleton().resourceExists(resource_uri, ROS_PACKAGE_NAME)) { + return Ogre::MeshManager::getSingleton().getByName(resource_uri, ROS_PACKAGE_NAME); + } - const aiScene * scene = assimp_loader.getScene(resource_path); - if (!scene) { - RVIZ_RENDERING_LOG_ERROR_STREAM( - "Could not load resource [" << resource_path.c_str() << "]: " << - assimp_loader.getErrorMessage()); - return Ogre::MeshPtr(); - } + // Check for ".mesh" resources, which OGRE can load directly + QFileInfo model_path(QString::fromStdString(resource_uri)); + std::string ext = model_path.completeSuffix().toStdString(); + if (ext == "mesh" || ext == "MESH") { + auto res = retriever->get(resource_uri); + if (res == nullptr || res->data.empty()) { + return nullptr; + } + Ogre::MeshSerializer ser; + Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(*res->data.data(), res->data.size())); + Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createManual(resource_uri, ROS_PACKAGE_NAME); + ser.importMesh(stream, mesh.get()); + stream->close(); + return mesh; + } - return assimp_loader.meshFromAssimpScene(resource_path, scene); + { + AssimpLoader assimp_loader(retriever); + const aiScene * scene = assimp_loader.getScene(resource_uri); + if (scene == nullptr) { + RVIZ_RENDERING_LOG_ERROR_STREAM( + "Could not load resource [" << resource_uri.c_str() << "]: " << + assimp_loader.getErrorMessage()); + return nullptr; } + return assimp_loader.meshFromAssimpScene(resource_uri, scene); } } diff --git a/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.cpp b/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.cpp index ae74a5d41..b0e8c02fb 100644 --- a/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.cpp +++ b/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.cpp @@ -69,9 +69,9 @@ namespace rviz_rendering class ResourceIOStream : public Assimp::IOStream { public: - explicit ResourceIOStream(const resource_retriever::MemoryResource & res) + explicit ResourceIOStream(resource_retriever::MemoryResourcePtr res) : res_(res), - pos_(res.data.get()) + pos_(res->data.data()) {} ~ResourceIOStream() override = default; @@ -79,8 +79,8 @@ class ResourceIOStream : public Assimp::IOStream size_t Read(void * buffer, size_t size, size_t count) override { size_t to_read = size * count; - if (pos_ + to_read > res_.data.get() + res_.size) { - to_read = res_.size - (pos_ - res_.data.get()); + if (pos_ + to_read > res_->data.data() + res_->data.size()) { + to_read = res_->data.size()- (pos_ - res_->data.data()); } memcpy(buffer, pos_, to_read); @@ -99,22 +99,22 @@ class ResourceIOStream : public Assimp::IOStream aiReturn Seek(size_t offset, aiOrigin origin) override { - uint8_t * new_pos = nullptr; + const uint8_t * new_pos = nullptr; switch (origin) { case aiOrigin_SET: - new_pos = res_.data.get() + offset; + new_pos = res_->data.data() + offset; break; case aiOrigin_CUR: new_pos = pos_ + offset; // TODO(anyone): is this right? Can offset really not be negative break; case aiOrigin_END: - new_pos = res_.data.get() + res_.size - offset; // TODO(anyone): is this right? + new_pos = res_->data.data() + res_->data.size() - offset; // TODO(anyone): is this right? break; default: throw std::runtime_error("unexpected default in switch statement"); } - if (new_pos < res_.data.get() || new_pos > res_.data.get() + res_.size) { + if (new_pos < res_->data.data() || new_pos > res_->data.data() + res_->data.size()) { return aiReturn_FAILURE; } @@ -124,26 +124,30 @@ class ResourceIOStream : public Assimp::IOStream size_t Tell() const override { - return pos_ - res_.data.get(); + return pos_ - res_->data.data(); } size_t FileSize() const override { - return res_.size; + return res_->data.size(); } void Flush() override {} private: - resource_retriever::MemoryResource res_; - uint8_t * pos_; + resource_retriever::MemoryResourcePtr res_; + const uint8_t * pos_; }; class ResourceIOSystem final : public Assimp::IOSystem { public: - ResourceIOSystem() = default; + explicit ResourceIOSystem(resource_retriever::Retriever * retriever): + retriever_(retriever) + { + } + ~ResourceIOSystem() override = default; @@ -156,32 +160,24 @@ class ResourceIOSystem final : public Assimp::IOSystem // Check whether a specific file exists bool Exists(const char * file) const override { - try { - resource_retriever::MemoryResource res = retriever_.get(file); - } catch (const resource_retriever::Exception & e) { - (void) e; // do nothing on exception - return false; - } - - return true; + auto res = retriever_->get(file); + return res != nullptr; } // ... and finally a method to open a custom stream - Assimp::IOStream * Open(const char * file, const char * mode = "rb") override + Assimp::IOStream * Open(const char * file, const char * mode) override { (void) mode; assert(mode == std::string("r") || mode == std::string("rb")); - resource_retriever::MemoryResource res; - try { - res = retriever_.get(file); - } catch (const resource_retriever::Exception & e) { - (void) e; // do nothing on exception - return nullptr; + auto res = retriever_->get(file); + + if (res != nullptr) { + // This will get freed when 'Close' is called + return new ResourceIOStream(res); } - // This will get freed when 'Close' is called - return new ResourceIOStream(res); + return nullptr; } void Close(Assimp::IOStream * stream) override @@ -190,13 +186,14 @@ class ResourceIOSystem final : public Assimp::IOSystem } private: - mutable resource_retriever::Retriever retriever_; + resource_retriever::Retriever * retriever_; }; -AssimpLoader::AssimpLoader() +AssimpLoader::AssimpLoader(resource_retriever::Retriever * retriever): + retriever_(retriever), + importer_(std::make_unique()) { - importer_ = std::make_unique(); - importer_->SetIOHandler(new ResourceIOSystem()); + importer_->SetIOHandler(new ResourceIOSystem(retriever_)); // ASSIMP wants to change the orientation of the axis, but that's wrong for rviz. importer_->SetPropertyBool(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, true); } @@ -397,31 +394,26 @@ void AssimpLoader::loadEmbeddedTexture( void AssimpLoader::loadTexture(const std::string & resource_path) { if (!Ogre::TextureManager::getSingleton().resourceExists(resource_path, ROS_PACKAGE_NAME)) { - resource_retriever::Retriever retriever; - resource_retriever::MemoryResource res; - try { - res = retriever.get(resource_path); - } catch (resource_retriever::Exception & e) { - RVIZ_RENDERING_LOG_ERROR(e.what()); - } + auto res = retriever_->get(resource_path); - if (res.size != 0) { - Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(res.data.get(), res.size)); - Ogre::Image image; - QFileInfo resource_path_finfo(QString::fromStdString(resource_path)); - std::string extension = resource_path_finfo.completeSuffix().toStdString(); + if (res == nullptr || res->data.empty()) + return; - if (extension[0] == '.') { - extension = extension.substr(1, extension.size() - 1); - } + Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(const_cast(res->data.data()), res->data.size())); + Ogre::Image image; + QFileInfo resource_path_finfo(QString::fromStdString(resource_path)); + std::string extension = resource_path_finfo.completeSuffix().toStdString(); - try { - image.load(stream, extension); - Ogre::TextureManager::getSingleton().loadImage(resource_path, ROS_PACKAGE_NAME, image); - } catch (Ogre::Exception & e) { - RVIZ_RENDERING_LOG_ERROR_STREAM( - "Could not load texture [" << resource_path.c_str() << "]: " << e.what()); - } + if (extension[0] == '.') { + extension = extension.substr(1, extension.size() - 1); + } + + try { + image.load(stream, extension); + Ogre::TextureManager::getSingleton().loadImage(resource_path, ROS_PACKAGE_NAME, image); + } catch (Ogre::Exception & e) { + RVIZ_RENDERING_LOG_ERROR_STREAM( + "Could not load texture [" << resource_path.c_str() << "]: " << e.what()); } } } diff --git a/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.hpp b/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.hpp index 5737dfb69..a27b07b87 100644 --- a/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.hpp +++ b/rviz_rendering/src/rviz_rendering/mesh_loader_helpers/assimp_loader.hpp @@ -60,7 +60,7 @@ namespace rviz_rendering class AssimpLoader { public: - AssimpLoader(); + explicit AssimpLoader(resource_retriever::Retriever * retriever = nullptr); Ogre::MeshPtr meshFromAssimpScene(const std::string & name, const aiScene * scene); const aiScene * getScene(const std::string & resource_path); std::string getErrorMessage(); @@ -151,6 +151,7 @@ class AssimpLoader index_buffer->unlock(); } + resource_retriever::Retriever * retriever_; std::unique_ptr importer_; };