From 449f644df503dc409514cafd7b46ee8664e4d451 Mon Sep 17 00:00:00 2001 From: Tomi Korpipaa Date: Thu, 25 Aug 2022 09:07:45 +0300 Subject: Do not crash if custom object load fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was no check for the existence of UVs or normals in an OBJ file. A check for those was added. Additionally a debug message was added in case model loading fails due to missing UVs or normals. Furthermore, we no more qFatal out when custom object loading fails. Pick-to: 6.2 6.4 Fixes: QTBUG-105398 Change-Id: Ie2742fb4307fe117e313cedf8111bc8f460f9c7b Reviewed-by: Sami Varanka Reviewed-by: Kwanghyo Park Reviewed-by: Dilek Akcay Reviewed-by: Tomi Korpipää --- src/datavisualization/data/customrenderitem.cpp | 3 +- src/datavisualization/data/customrenderitem_p.h | 2 +- src/datavisualization/data/qcustom3ditem.cpp | 7 +- .../engine/abstract3drenderer.cpp | 11 ++- src/datavisualization/utils/meshloader.cpp | 4 + src/datavisualization/utils/objecthelper.cpp | 86 ++++++++++++---------- 6 files changed, 70 insertions(+), 43 deletions(-) diff --git a/src/datavisualization/data/customrenderitem.cpp b/src/datavisualization/data/customrenderitem.cpp index fccf6b9a..9873bcf5 100644 --- a/src/datavisualization/data/customrenderitem.cpp +++ b/src/datavisualization/data/customrenderitem.cpp @@ -42,9 +42,10 @@ CustomRenderItem::~CustomRenderItem() ObjectHelper::releaseObjectHelper(m_renderer, m_object); } -void CustomRenderItem::setMesh(const QString &meshFile) +bool CustomRenderItem::setMesh(const QString &meshFile) { ObjectHelper::resetObjectHelper(m_renderer, m_object, meshFile); + return m_object ? true : false; } void CustomRenderItem::setColorTable(const QList &colors) diff --git a/src/datavisualization/data/customrenderitem_p.h b/src/datavisualization/data/customrenderitem_p.h index ff9b06bf..abc62247 100644 --- a/src/datavisualization/data/customrenderitem_p.h +++ b/src/datavisualization/data/customrenderitem_p.h @@ -33,7 +33,7 @@ public: inline void setTexture(GLuint texture) { m_texture = texture; } inline GLuint texture() const { return m_texture; } - void setMesh(const QString &meshFile); + bool setMesh(const QString &meshFile); inline ObjectHelper *mesh() const { return m_object; } inline void setScaling(const QVector3D &scaling) { m_scaling = scaling; } inline const QVector3D &scaling() const { return m_scaling; } diff --git a/src/datavisualization/data/qcustom3ditem.cpp b/src/datavisualization/data/qcustom3ditem.cpp index a9cfd5de..a657823c 100644 --- a/src/datavisualization/data/qcustom3ditem.cpp +++ b/src/datavisualization/data/qcustom3ditem.cpp @@ -32,7 +32,9 @@ QT_BEGIN_NAMESPACE /*! \qmlproperty string Custom3DItem::meshFile * * The item mesh file name. The item in the file must be in Wavefront OBJ format and include - * vertices, normals, and UVs. It also needs to be in triangles. + * vertices, normals, and UVs. It also needs to be in triangles. If the file is missing either + * normals or UVs, loading will fail with an error message to the console output and the item will + * not be rendered. */ /*! \qmlproperty string Custom3DItem::textureFile @@ -177,6 +179,9 @@ QCustom3DItem::~QCustom3DItem() * * The item in the file must be in Wavefront OBJ format and include * vertices, normals, and UVs. It also needs to be in triangles. + * If the file is missing either normals or UVs, loading will fail + * with an error message to the console output and the item will + * not be rendered. */ void QCustom3DItem::setMeshFile(const QString &meshFile) { diff --git a/src/datavisualization/engine/abstract3drenderer.cpp b/src/datavisualization/engine/abstract3drenderer.cpp index 4ddd19e8..b7a37a20 100644 --- a/src/datavisualization/engine/abstract3drenderer.cpp +++ b/src/datavisualization/engine/abstract3drenderer.cpp @@ -723,8 +723,10 @@ void Abstract3DRenderer::updateCustomData(const QList &customIt CustomRenderItem *renderItem = m_customRenderCache.value(item); if (!renderItem) renderItem = addCustomItem(item); - renderItem->setValid(true); - renderItem->setIndex(i); // always update index, as it must match the custom item index + if (renderItem) { + renderItem->setValid(true); + renderItem->setIndex(i); // always update index, as it must match the custom item index + } } // Check render item cache and remove items that are not in customItems list anymore @@ -1127,7 +1129,10 @@ CustomRenderItem *Abstract3DRenderer::addCustomItem(QCustom3DItem *item) CustomRenderItem *newItem = new CustomRenderItem(); newItem->setRenderer(this); newItem->setItemPointer(item); // Store pointer for render item updates - newItem->setMesh(item->meshFile()); + if (!newItem->setMesh(item->meshFile())) { + delete newItem; + return nullptr; + } newItem->setOrigPosition(item->position()); newItem->setOrigScaling(item->scaling()); newItem->setScalingAbsolute(item->isScalingAbsolute()); diff --git a/src/datavisualization/utils/meshloader.cpp b/src/datavisualization/utils/meshloader.cpp index 8b3b0725..baa719bc 100644 --- a/src/datavisualization/utils/meshloader.cpp +++ b/src/datavisualization/utils/meshloader.cpp @@ -55,6 +55,10 @@ bool MeshLoader::loadOBJ(const QString &path, QList &out_vertices, QStringList set1 = lineContents.at(1).split(slashTag); QStringList set2 = lineContents.at(2).split(slashTag); QStringList set3 = lineContents.at(3).split(slashTag); + if (set1.length() < 3 || set2.length() < 3 || set3.length() < 3) { + qWarning("The file being loaded is missing UVs and/or normals"); + return false; + } vertexIndex[0] = set1.at(0).toUInt(); vertexIndex[1] = set2.at(0).toUInt(); vertexIndex[2] = set3.at(0).toUInt(); diff --git a/src/datavisualization/utils/objecthelper.cpp b/src/datavisualization/utils/objecthelper.cpp index 893e65c0..6053b255 100644 --- a/src/datavisualization/utils/objecthelper.cpp +++ b/src/datavisualization/utils/objecthelper.cpp @@ -87,10 +87,19 @@ ObjectHelper *ObjectHelper::getObjectHelper(const Abstract3DRenderer *cacheId, objRef = new ObjectHelperRef; objRef->refCount = 0; objRef->obj = new ObjectHelper(objectFile); - objectTable->insert(objectFile, objRef); + if (objRef->obj->m_meshDataLoaded) { + objectTable->insert(objectFile, objRef); + } else { + delete objRef->obj; + delete objRef; + objRef = nullptr; + } + } + if (objRef) { + objRef->refCount++; + return objRef->obj; } - objRef->refCount++; - return objRef->obj; + return nullptr; } void ObjectHelper::load() @@ -114,41 +123,44 @@ void ObjectHelper::load() QList uvs; QList normals; bool loadOk = MeshLoader::loadOBJ(m_objectFile, vertices, uvs, normals); - if (!loadOk) - qFatal("loading failed"); - - // Index vertices - VertexIndexer::indexVBO(vertices, uvs, normals, m_indices, m_indexedVertices, m_indexedUVs, - m_indexedNormals); - - m_indexCount = m_indices.size(); - - glGenBuffers(1, &m_vertexbuffer); - glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer); - glBufferData(GL_ARRAY_BUFFER, m_indexedVertices.size() * sizeof(QVector3D), - &m_indexedVertices.at(0), - GL_STATIC_DRAW); - glGenBuffers(1, &m_normalbuffer); - glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer); - glBufferData(GL_ARRAY_BUFFER, m_indexedNormals.size() * sizeof(QVector3D), - &m_indexedNormals.at(0), - GL_STATIC_DRAW); - - glGenBuffers(1, &m_uvbuffer); - glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); - glBufferData(GL_ARRAY_BUFFER, m_indexedUVs.size() * sizeof(QVector2D), - &m_indexedUVs.at(0), GL_STATIC_DRAW); - - glGenBuffers(1, &m_elementbuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(GLuint), - &m_indices.at(0), GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - m_meshDataLoaded = true; + if (!loadOk) { + qCritical() << "Loading" << m_objectFile << "failed"; + m_meshDataLoaded = false; + } else { + // Index vertices + VertexIndexer::indexVBO(vertices, uvs, normals, m_indices, m_indexedVertices, m_indexedUVs, + m_indexedNormals); + + m_indexCount = m_indices.size(); + + glGenBuffers(1, &m_vertexbuffer); + glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer); + glBufferData(GL_ARRAY_BUFFER, m_indexedVertices.size() * sizeof(QVector3D), + &m_indexedVertices.at(0), + GL_STATIC_DRAW); + + glGenBuffers(1, &m_normalbuffer); + glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer); + glBufferData(GL_ARRAY_BUFFER, m_indexedNormals.size() * sizeof(QVector3D), + &m_indexedNormals.at(0), + GL_STATIC_DRAW); + + glGenBuffers(1, &m_uvbuffer); + glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer); + glBufferData(GL_ARRAY_BUFFER, m_indexedUVs.size() * sizeof(QVector2D), + &m_indexedUVs.at(0), GL_STATIC_DRAW); + + glGenBuffers(1, &m_elementbuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices.size() * sizeof(GLuint), + &m_indices.at(0), GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + m_meshDataLoaded = true; + } } QT_END_NAMESPACE -- cgit v1.2.3