Skip to content

Commit

Permalink
Prevent Scene3D 💥 if another scene is already loaded (#347)
Browse files Browse the repository at this point in the history
Signed-off-by: Louise Poubel <[email protected]>
  • Loading branch information
chapulina authored Jan 10, 2022
1 parent 9af7abf commit 419613d
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 24 deletions.
90 changes: 76 additions & 14 deletions src/plugins/scene3d/Scene3D.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1059,19 +1059,37 @@ void IgnRenderer::BroadcastRightClick()
}

/////////////////////////////////////////////////
void IgnRenderer::Initialize()
std::string IgnRenderer::Initialize()
{
if (this->initialized)
return;
return std::string();

// Currently only support one engine at a time
rendering::RenderEngine *engine{nullptr};
auto loadedEngines = rendering::loadedEngines();

// Load engine if there's no engine yet
if (loadedEngines.empty())
{
std::map<std::string, std::string> params;
params["useCurrentGLContext"] = "1";
engine = rendering::engine(this->engineName, params);
}
else
{
if (loadedEngines.front() != this->engineName)
{
ignwarn << "Failed to load engine [" << this->engineName
<< "]. Using engine [" << loadedEngines.front()
<< "], which is already loaded. Currently only one engine is "
<< "supported at a time." << std::endl;
}
engine = rendering::engine(loadedEngines.front());
}

std::map<std::string, std::string> params;
params["useCurrentGLContext"] = "1";
auto engine = rendering::engine(this->engineName, params);
if (!engine)
{
ignerr << "Engine [" << this->engineName << "] is not supported"
<< std::endl;
return;
return "Engine [" + this->engineName + "] is not supported";
}

// Scene
Expand All @@ -1083,6 +1101,11 @@ void IgnRenderer::Initialize()
scene->SetAmbientLight(this->ambientLight);
scene->SetBackgroundColor(this->backgroundColor);
}
else
{
return "Currently only one plugin providing a 3D scene is supported at a "
"time.";
}

auto root = scene->RootVisual();

Expand Down Expand Up @@ -1112,6 +1135,7 @@ void IgnRenderer::Initialize()
this->dataPtr->rayQuery = this->dataPtr->camera->Scene()->CreateRayQuery();

this->initialized = true;
return std::string();
}

/////////////////////////////////////////////////
Expand Down Expand Up @@ -1183,6 +1207,12 @@ RenderThread::RenderThread()
RenderWindowItemPrivate::threads << this;
}

/////////////////////////////////////////////////
void RenderThread::SetErrorCb(std::function<void(const QString&)> _cb)
{
this->errorCb = _cb;
}

/////////////////////////////////////////////////
void RenderThread::RenderNext()
{
Expand All @@ -1191,7 +1221,12 @@ void RenderThread::RenderNext()
if (!this->ignRenderer.initialized)
{
// Initialize renderer
this->ignRenderer.Initialize();
auto loadingError = this->ignRenderer.Initialize();
if (!loadingError.empty())
{
this->errorCb(QString::fromStdString(loadingError));
return;
}
}

// check if engine has been successfully initialized
Expand All @@ -1209,18 +1244,24 @@ void RenderThread::RenderNext()
/////////////////////////////////////////////////
void RenderThread::ShutDown()
{
this->context->makeCurrent(this->surface);
if (this->context && this->surface)
this->context->makeCurrent(this->surface);

this->ignRenderer.Destroy();

this->context->doneCurrent();
delete this->context;
if (this->context)
{
this->context->doneCurrent();
delete this->context;
}

// schedule this to be deleted only after we're done cleaning up
this->surface->deleteLater();
if (this->surface)
this->surface->deleteLater();

// Stop event processing, move the thread to GUI and make sure it is deleted.
this->moveToThread(QGuiApplication::instance()->thread());
if (this->ignRenderer.initialized)
this->moveToThread(QGuiApplication::instance()->thread());
}


Expand Down Expand Up @@ -1500,6 +1541,8 @@ void Scene3D::LoadConfig(const tinyxml2::XMLElement *_pluginElem)
<< "Render window will not be created" << std::endl;
return;
}
renderWindow->SetErrorCb(std::bind(&Scene3D::SetLoadingError, this,
std::placeholders::_1));

if (this->title.empty())
this->title = "3D Scene";
Expand Down Expand Up @@ -1588,6 +1631,12 @@ void RenderWindowItem::OnHovered(const ignition::math::Vector2i &_hoverPos)
this->dataPtr->renderThread->ignRenderer.NewHoverEvent(_hoverPos);
}

/////////////////////////////////////////////////
void RenderWindowItem::SetErrorCb(std::function<void(const QString&)> _cb)
{
this->dataPtr->renderThread->SetErrorCb(_cb);
}

/////////////////////////////////////////////////
void RenderWindowItem::mousePressEvent(QMouseEvent *_e)
{
Expand Down Expand Up @@ -1690,6 +1739,19 @@ void Scene3D::OnFocusWindow()
renderWindow->forceActiveFocus();
}

/////////////////////////////////////////////////
QString Scene3D::LoadingError() const
{
return this->loadingError;
}

/////////////////////////////////////////////////
void Scene3D::SetLoadingError(const QString &_loadingError)
{
this->loadingError = _loadingError;
this->LoadingErrorChanged();
}

// Register this plugin
IGNITION_ADD_PLUGIN(ignition::gui::plugins::Scene3D,
ignition::gui::Plugin)
48 changes: 44 additions & 4 deletions src/plugins/scene3d/Scene3D.hh
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,18 @@ namespace plugins
class RenderWindowItemPrivate;
class Scene3DPrivate;

/// \brief Creates a new ignition rendering scene or adds a user-camera to an
/// existing scene. It is possible to orbit the camera around the scene with
/// \brief Creates an ignition rendering scene and user camera.
/// It is possible to orbit the camera around the scene with
/// the mouse. Use other plugins to manage objects in the scene.
///
/// Only one plugin displaying an Ignition Rendering scene can be used at a
/// time.
///
/// ## Configuration
///
/// * \<engine\> : Optional render engine name, defaults to 'ogre'.
/// * \<engine\> : Optional render engine name, defaults to 'ogre'. If another
/// engine is already loaded, that will be used, because only
/// one engine is supported at a time currently.
/// * \<scene\> : Optional scene name, defaults to 'scene'. The plugin will
/// create a scene with this name if there isn't one yet. If
/// there is already one, a new camera is added to it.
Expand All @@ -62,6 +67,14 @@ namespace plugins
{
Q_OBJECT

/// \brief Loading error message
Q_PROPERTY(
QString loadingError
READ LoadingError
WRITE SetLoadingError
NOTIFY LoadingErrorChanged
)

/// \brief Constructor
public: Scene3D();

Expand All @@ -84,6 +97,20 @@ namespace plugins
public: virtual void LoadConfig(const tinyxml2::XMLElement *_pluginElem)
override;

/// \brief Get the loading error string.
/// \return String explaining the loading error. If empty, there's no error.
public: Q_INVOKABLE QString LoadingError() const;

/// \brief Set the loading error message.
/// \param[in] _loadingError Error message.
public: Q_INVOKABLE void SetLoadingError(const QString &_loadingError);

/// \brief Notify that loading error has changed
signals: void LoadingErrorChanged();

/// \brief Loading error message
public: QString loadingError;

/// \internal
/// \brief Pointer to private data.
private: std::unique_ptr<Scene3DPrivate> dataPtr;
Expand All @@ -107,7 +134,9 @@ namespace plugins
public: void Render();

/// \brief Initialize the render engine
public: void Initialize();
/// \return Error message if initialization failed. If empty, no errors
/// occurred.
public: std::string Initialize();

/// \brief Destroy camera associated with this renderer
public: void Destroy();
Expand Down Expand Up @@ -224,6 +253,13 @@ namespace plugins
/// \param[in] _size Size of the texture
signals: void TextureReady(int _id, const QSize &_size);

/// \brief Set a callback to be called in case there are errors.
/// \param[in] _cb Error callback
public: void SetErrorCb(std::function<void(const QString &)> _cb);

/// \brief Function to be called if there are errors.
public: std::function<void(const QString &)> errorCb;

/// \brief Offscreen surface to render to
public: QOffscreenSurface *surface = nullptr;

Expand Down Expand Up @@ -327,6 +363,10 @@ namespace plugins
private: QSGNode *updatePaintNode(QSGNode *_oldNode,
QQuickItem::UpdatePaintNodeData *_data) override;

/// \brief Set a callback to be called in case there are errors.
/// \param[in] _cb Error callback
public: void SetErrorCb(std::function<void(const QString &)> _cb);

/// \internal
/// \brief Pointer to private data.
private: std::unique_ptr<RenderWindowItemPrivate> dataPtr;
Expand Down
18 changes: 15 additions & 3 deletions src/plugins/scene3d/Scene3D.qml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@
* limitations under the License.
*
*/
import QtGraphicalEffects 1.0
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import RenderWindow 1.0
import QtGraphicalEffects 1.0

Rectangle {
width: 1000
height: 800
Layout.minimumWidth: 200
Layout.minimumHeight: 200
anchors.fill: parent

/**
* True to enable gamma correction
Expand All @@ -36,6 +38,7 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
visible: Scene3D.loadingError.length == 0
onEntered: {
Scene3D.OnFocusWindow()
}
Expand All @@ -48,6 +51,7 @@ Rectangle {
id: renderWindow
objectName: "rw"
anchors.fill: parent
visible: Scene3D.loadingError.length == 0
}

/*
Expand All @@ -68,4 +72,12 @@ Rectangle {
width = Qt.binding(function() {return parent.parent.width})
height = Qt.binding(function() {return parent.parent.height})
}

Label {
anchors.fill: parent
anchors.margins: 10
text: Scene3D.loadingError
visible: (Scene3D.loadingError.length > 0);
wrapMode: Text.WordWrap
}
}
6 changes: 3 additions & 3 deletions test/integration/scene3d.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ TEST(Scene3DTest, IGN_UTILS_TEST_ENABLED_ONLY_ON_LINUX(Events))
EXPECT_TRUE(receivedHoverEvent);

EXPECT_EQ(leftClickPoint, rightClickPoint);
EXPECT_NEAR(1.0, leftClickPoint.X(), 1e-4);
EXPECT_NEAR(11.942695, leftClickPoint.Y(), 1e-4);
EXPECT_NEAR(4.159424, leftClickPoint.Z(), 1e-4);
EXPECT_NEAR(1.0, leftClickPoint.X(), 1e-3);
EXPECT_NEAR(11.942695, leftClickPoint.Y(), 1e-1);
EXPECT_NEAR(4.159424, leftClickPoint.Z(), 0.5);
}

0 comments on commit 419613d

Please sign in to comment.