Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestions to #170 #171

Merged
merged 3 commits into from
Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 0 additions & 60 deletions src/plugins/scene3d/Scene3D.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <vector>

#include <ignition/common/Console.hh>
#include <ignition/common/Image.hh>
#include <ignition/common/MouseEvent.hh>
#include <ignition/plugin/Register.hh>
#include <ignition/common/MeshManager.hh>
Expand Down Expand Up @@ -231,9 +230,6 @@ namespace plugins

/// \brief View control focus target
public: math::Vector3d target;

/// \brief Path to save the screenshot
public: std::string screenshotSavePath;
};

/// \brief Private data class for RenderWindowItem
Expand All @@ -252,11 +248,6 @@ namespace plugins
/// \brief Private data class for Scene3D
class Scene3DPrivate
{
/// \brief Transport node
public: transport::Node node;

/// \brief Screenshot service
public: std::string screenshotService;
};
}
}
Expand Down Expand Up @@ -861,25 +852,6 @@ void IgnRenderer::Render()
// update and render to texture
this->dataPtr->camera->Update();

// Save screenshot
{
if (!this->dataPtr->screenshotSavePath.empty())
{
unsigned int width = this->dataPtr->camera->ImageWidth();
unsigned int height = this->dataPtr->camera->ImageHeight();

auto cameraImage = this->dataPtr->camera->CreateImage();
this->dataPtr->camera->Copy(cameraImage);

common::Image image;
image.SetFromData(cameraImage.Data<unsigned char>(), width, height,
common::Image::RGB_INT8);
image.SavePNG(this->dataPtr->screenshotSavePath);

this->dataPtr->screenshotSavePath.clear();
}
}

if (ignition::gui::App())
{
ignition::gui::App()->sendEvent(
Expand All @@ -888,13 +860,6 @@ void IgnRenderer::Render()
}
}

/////////////////////////////////////////////////
void IgnRenderer::SaveScreenshot(const std::string &_filename)
{
std::lock_guard<std::mutex> lock(this->dataPtr->mutex);
this->dataPtr->screenshotSavePath = _filename;
}

/////////////////////////////////////////////////
void IgnRenderer::HandleMouseEvent()
{
Expand Down Expand Up @@ -1467,26 +1432,8 @@ void Scene3D::LoadConfig(const tinyxml2::XMLElement *_pluginElem)
renderWindow->SetSceneTopic(topic);
}
}

// Screenshot service
this->dataPtr->screenshotService = "/gui/screenshot";
this->dataPtr->node.Advertise(this->dataPtr->screenshotService,
&Scene3D::OnScreenshot, this);
ignmsg << "Screenshot service on ["
<< this->dataPtr->screenshotService << "]" << std::endl;
}

/////////////////////////////////////////////////
bool Scene3D::OnScreenshot(const msgs::StringMsg &_msg,
msgs::Boolean &_res)
{
auto renderWindow = this->PluginItem()->findChild<RenderWindowItem *>();
renderWindow->SaveScreenshot(_msg.data());
_res.set_data(true);
return true;
}


/////////////////////////////////////////////////
void RenderWindowItem::mousePressEvent(QMouseEvent *_e)
{
Expand Down Expand Up @@ -1537,13 +1484,6 @@ void RenderWindowItem::wheelEvent(QWheelEvent *_e)
this->dataPtr->mouseEvent, math::Vector2d(scroll, scroll));
}

/////////////////////////////////////////////////
void RenderWindowItem::SaveScreenshot(const std::string &_filename)
{
this->dataPtr->renderThread->ignRenderer.SaveScreenshot(_filename);
}


///////////////////////////////////////////////////
// void Scene3D::resizeEvent(QResizeEvent *_e)
// {
Expand Down
15 changes: 0 additions & 15 deletions src/plugins/scene3d/Scene3D.hh
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,6 @@ namespace plugins
public: virtual void LoadConfig(const tinyxml2::XMLElement *_pluginElem)
override;

/// \brief Callback for saving a screenshot (from the user camera) request
/// \param[in] _msg Request message of the saved file path
/// \param[in] _res Response data
/// \return True if the request is received
private: bool OnScreenshot(const msgs::StringMsg &_msg,
msgs::Boolean &_res);

/// \internal
/// \brief Pointer to private data.
private: std::unique_ptr<Scene3DPrivate> dataPtr;
Expand Down Expand Up @@ -126,10 +119,6 @@ namespace plugins
private: math::Vector3d ScreenToScene(const math::Vector2i &_screenPos)
const;

/// \brief Save a screenshot from the user camera
/// \param[in] _filename The filename (including path) of the screenshot
public: void SaveScreenshot(const std::string &_filename);

/// \brief Render texture id
public: GLuint textureId = 0u;

Expand Down Expand Up @@ -271,10 +260,6 @@ namespace plugins
/// \brief Slot called when thread is ready to be started
public Q_SLOTS: void Ready();

/// \brief Save a screenshot from the user camera
/// \param[in] _filename The filename (including path) of the screenshot
public: void SaveScreenshot(const std::string &_filename);

// Documentation inherited
protected: virtual void mousePressEvent(QMouseEvent *_e) override;

Expand Down
2 changes: 2 additions & 0 deletions src/plugins/screenshot/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ ign_gui_add_plugin(Screenshot
Screenshot.cc
QT_HEADERS
Screenshot.hh
PUBLIC_LINK_LIBS
ignition-rendering${IGN_RENDERING_VER}::ignition-rendering${IGN_RENDERING_VER}
)
156 changes: 140 additions & 16 deletions src/plugins/screenshot/Screenshot.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,17 @@

#include <ignition/common/Console.hh>
#include <ignition/common/Filesystem.hh>
#include <ignition/common/Image.hh>
#include <ignition/plugin/Register.hh>
#include <ignition/rendering/Camera.hh>
#include <ignition/rendering/RenderEngine.hh>
#include <ignition/rendering/RenderingIface.hh>
#include <ignition/rendering/Scene.hh>
#include <ignition/transport/Node.hh>

#include "ignition/gui/Application.hh"
#include "ignition/gui/GuiEvents.hh"
#include "ignition/gui/MainWindow.hh"

namespace ignition
{
Expand All @@ -44,6 +51,12 @@ namespace plugins

/// \brief Directory to save screenshots
public: std::string directory;

/// \brief Whether a screenshot has been requested but not processed yet.
public: bool dirty{false};

/// \brief Pointer to the user camera.
public: ignition::rendering::CameraPtr userCamera{nullptr};
};
}
}
Expand All @@ -58,21 +71,18 @@ Screenshot::Screenshot()
: ignition::gui::Plugin(),
dataPtr(std::make_unique<ScreenshotPrivate>())
{
// for screenshot requests
this->dataPtr->screenshotService = "/gui/screenshot";

std::string home;
common::env(IGN_HOMEDIR, home);

// default directory
this->dataPtr->directory =
common::joinPaths(home, ".ignition", "gazebo", "pictures");
common::joinPaths(home, ".ignition", "gui", "pictures");

if (!common::exists(this->dataPtr->directory))
{
if (!common::createDirectory(this->dataPtr->directory))
if (!common::createDirectories(this->dataPtr->directory))
{
std::string defaultDir = common::joinPaths(home, ".ignition", "gazebo");
std::string defaultDir = common::joinPaths(home, ".ignition", "gui");
ignerr << "Unable to create directory [" << this->dataPtr->directory
<< "]. Changing default directory to: " << defaultDir
<< std::endl;
Expand All @@ -94,24 +104,138 @@ void Screenshot::LoadConfig(const tinyxml2::XMLElement *)
{
if (this->title.empty())
this->title = "Screenshot";

// Screenshot service
this->dataPtr->screenshotService = "/gui/screenshot";
this->dataPtr->node.Advertise(this->dataPtr->screenshotService,
&Screenshot::ScreenshotService, this);
ignmsg << "Screenshot service on ["
<< this->dataPtr->screenshotService << "]" << std::endl;

App()->findChild<MainWindow *>()->installEventFilter(this);
}

/////////////////////////////////////////////////
void Screenshot::OnScreenshot()
bool Screenshot::eventFilter(QObject *_obj, QEvent *_event)
{
std::function<void(const ignition::msgs::Boolean &, const bool)> cb =
[](const ignition::msgs::Boolean &/*_rep*/, const bool _result)
if (_event->type() == events::Render::kType && this->dataPtr->dirty)
{
if (!_result)
ignerr << "Error sending move to request" << std::endl;
};
this->SaveScreenshot();
}

// Standard event processing
return QObject::eventFilter(_obj, _event);
}

/////////////////////////////////////////////////
bool Screenshot::ScreenshotService(const msgs::StringMsg &_msg,
msgs::Boolean &_res)
{
if (!_msg.data().empty())
this->dataPtr->directory = _msg.data();
this->dataPtr->dirty = true;
_res.set_data(true);
return true;
}

/////////////////////////////////////////////////
void Screenshot::SaveScreenshot()
{
this->FindUserCamera();

if (nullptr == this->dataPtr->userCamera)
return;

unsigned int width = this->dataPtr->userCamera->ImageWidth();
unsigned int height = this->dataPtr->userCamera->ImageHeight();

auto cameraImage = this->dataPtr->userCamera->CreateImage();
this->dataPtr->userCamera->Copy(cameraImage);

std::string time = common::systemTimeISO() + ".png";
std::string savedPath = common::joinPaths(this->dataPtr->directory, time);
std::string savePath = common::joinPaths(this->dataPtr->directory, time);

common::Image image;
image.SetFromData(cameraImage.Data<unsigned char>(), width, height,
common::Image::RGB_INT8);
image.SavePNG(savePath);

igndbg << "Saved image to [" << savePath << "]" << std::endl;

this->dataPtr->dirty = false;
}

/////////////////////////////////////////////////
void Screenshot::FindUserCamera()
{
if (nullptr != this->dataPtr->userCamera)
return;

ignition::msgs::StringMsg req;
req.set_data(savedPath);
this->dataPtr->node.Request(this->dataPtr->screenshotService, req, cb);
auto loadedEngNames = ignition::rendering::loadedEngines();
if (loadedEngNames.empty())
{
igndbg << "No rendering engine is loaded yet" << std::endl;
return;
}

// assume there is only one engine loaded
auto engineName = loadedEngNames[0];
if (loadedEngNames.size() > 1)
{
igndbg << "More than one engine is available. "
<< "Using engine [" << engineName << "]" << std::endl;
}
auto engine = ignition::rendering::engine(engineName);
if (!engine)
{
ignerr << "Internal error: failed to load engine [" << engineName
<< "]. Grid plugin won't work." << std::endl;
return;
}

if (engine->SceneCount() == 0)
{
igndbg << "No scene has been created yet" << std::endl;
return;
}

// Get first scene
auto scene = engine->SceneByIndex(0);
if (nullptr == scene)
{
ignerr << "Internal error: scene is null." << std::endl;
return;
}

if (engine->SceneCount() > 1)
{
igndbg << "More than one scene is available. "
<< "Using scene [" << scene->Name() << "]" << std::endl;
}

if (!scene->IsInitialized() || nullptr == scene->RootVisual())
{
return;
}

for (unsigned int i = 0; i < scene->NodeCount(); ++i)
{
auto cam = std::dynamic_pointer_cast<rendering::Camera>(
scene->NodeByIndex(i));
if (nullptr != cam)
{
this->dataPtr->userCamera = cam;
igndbg << "Screnshot plugin taking pictures of camera ["
<< this->dataPtr->userCamera->Name() << "]" << std::endl;
break;
}
}
}

/////////////////////////////////////////////////
void Screenshot::OnScreenshot()
{
this->dataPtr->dirty = true;
}

/////////////////////////////////////////////////
Expand Down
Loading