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

Prevent Scene3D 💥 if another scene is already loaded #347

Merged
merged 5 commits into from
Jan 10, 2022
Merged
Changes from 1 commit
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
Next Next commit
Prevent Scene3D crash if another scene is already loaded
Signed-off-by: Louise Poubel <[email protected]>
chapulina committed Jan 8, 2022
commit 3ce534b3cba14d10047c7b238728bd9f17b897b8
67 changes: 56 additions & 11 deletions src/plugins/scene3d/Scene3D.cc
Original file line number Diff line number Diff line change
@@ -1059,19 +1059,25 @@ void IgnRenderer::BroadcastRightClick()
}

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

// Only one engine / scene / user camera is currently supported.
// Fail gracefully.
if (!rendering::loadedEngines().empty())
{
return "Currently only one plugin providing a 3D scene is supported at a "
"time.";
}

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
@@ -1112,6 +1118,7 @@ void IgnRenderer::Initialize()
this->dataPtr->rayQuery = this->dataPtr->camera->Scene()->CreateRayQuery();

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

/////////////////////////////////////////////////
@@ -1183,6 +1190,12 @@ RenderThread::RenderThread()
RenderWindowItemPrivate::threads << this;
}

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

/////////////////////////////////////////////////
void RenderThread::RenderNext()
{
@@ -1191,7 +1204,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
@@ -1209,18 +1227,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());
}


@@ -1500,6 +1524,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";
@@ -1588,6 +1614,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)
{
@@ -1690,6 +1722,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)
44 changes: 41 additions & 3 deletions src/plugins/scene3d/Scene3D.hh
Original file line number Diff line number Diff line change
@@ -42,10 +42,13 @@ 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'.
@@ -62,6 +65,14 @@ namespace plugins
{
Q_OBJECT

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

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

@@ -84,6 +95,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;
@@ -107,7 +132,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();
@@ -224,6 +251,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;

@@ -327,6 +361,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;
18 changes: 15 additions & 3 deletions src/plugins/scene3d/Scene3D.qml
Original file line number Diff line number Diff line change
@@ -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
@@ -36,6 +38,7 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
visible: Scene3D.loadingError.length == 0
onEntered: {
Scene3D.OnFocusWindow()
}
@@ -48,6 +51,7 @@ Rectangle {
id: renderWindow
objectName: "rw"
anchors.fill: parent
visible: Scene3D.loadingError.length == 0
}

/*
@@ -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
}
}