diff options
author | Jonas Karlsson <jonas.karlsson@qt.io> | 2023-11-28 14:27:00 +0100 |
---|---|---|
committer | Jonas Karlsson <jonas.karlsson@qt.io> | 2023-12-06 16:18:03 +0100 |
commit | f43d8bf1aed47da1ae13d73d59e439ce6ef53348 (patch) | |
tree | a2b5c5b1fc15c311c6aa8fbfb2f81d4b92d9025d | |
parent | 3012a8a2b9c6bc5315f3a597300b5d447840c6a5 (diff) |
Move almost identical code into QMeshShape
QTriangleMeshShape and QConvexMeshShape are basically identical so move
the common code into a new class QMeshShape. Using an enum
ShapeType to differentiate the mesh types.
Pick-to: 6.6 6.5
Task-number: QTBUG-109818
Change-Id: Ia2e72eb84d14bcf1a38fa0d2df046805d175a5ad
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r-- | src/quick3dphysics/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/quick3dphysics/qconvexmeshshape.cpp | 292 | ||||
-rw-r--r-- | src/quick3dphysics/qconvexmeshshape_p.h | 39 | ||||
-rw-r--r-- | src/quick3dphysics/qmeshshape.cpp | 310 | ||||
-rw-r--r-- | src/quick3dphysics/qmeshshape_p.h | 69 | ||||
-rw-r--r-- | src/quick3dphysics/qtrianglemeshshape.cpp | 66 | ||||
-rw-r--r-- | src/quick3dphysics/qtrianglemeshshape_p.h | 40 |
7 files changed, 394 insertions, 423 deletions
diff --git a/src/quick3dphysics/CMakeLists.txt b/src/quick3dphysics/CMakeLists.txt index 350a4bd..541f636 100644 --- a/src/quick3dphysics/CMakeLists.txt +++ b/src/quick3dphysics/CMakeLists.txt @@ -34,6 +34,7 @@ qt_internal_add_qml_module(Quick3DPhysics qdebugdrawhelper.cpp qdebugdrawhelper_p.h qdynamicrigidbody.cpp qdynamicrigidbody_p.h qheightfieldshape.cpp qheightfieldshape_p.h + qmeshshape.cpp qmeshshape_p.h qphysicscommands.cpp qphysicscommands_p.h qphysicsmaterial.cpp qphysicsmaterial_p.h qphysicsmeshutils_p_p.h diff --git a/src/quick3dphysics/qconvexmeshshape.cpp b/src/quick3dphysics/qconvexmeshshape.cpp index a8a420e..cddeef9 100644 --- a/src/quick3dphysics/qconvexmeshshape.cpp +++ b/src/quick3dphysics/qconvexmeshshape.cpp @@ -1,248 +1,10 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only -#include "qcacheutils_p.h" #include "qconvexmeshshape_p.h" -#include <QFile> -#include <QFileInfo> -#include <QtQuick3D/QQuick3DGeometry> -#include <extensions/PxExtensionsAPI.h> - -#include "foundation/PxVec3.h" -#include "cooking/PxConvexMeshDesc.h" -#include "extensions/PxDefaultStreams.h" - -#include <QtQml/qqml.h> -#include <QtQml/QQmlFile> -#include <QtQml/qqmlcontext.h> - -#include <QtQuick3DUtils/private/qssgmesh_p.h> -#include "qphysicsworld_p.h" -#include "qphysicsmeshutils_p_p.h" -#include "qphysicsutils_p.h" - QT_BEGIN_NAMESPACE -physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMesh() -{ - if (m_convexMesh != nullptr) - return m_convexMesh; - - physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics(); - if (thePhysics == nullptr) - return nullptr; - - m_convexMesh = QCacheUtils::readCachedConvexMesh(m_meshPath, *thePhysics); - if (m_convexMesh != nullptr) - return m_convexMesh; - - m_convexMesh = QCacheUtils::readCookedConvexMesh(m_meshPath, *thePhysics); - if (m_convexMesh != nullptr) - return m_convexMesh; - - loadSsgMesh(); - - if (!m_ssgMesh.isValid()) - return nullptr; - - physx::PxDefaultMemoryOutputStream buf; - physx::PxConvexMeshCookingResult::Enum result; - int vStride = m_ssgMesh.vertexBuffer().stride; - int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride; - const auto *vd = m_ssgMesh.vertexBuffer().data.constData(); - - qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts"; - - QVector<physx::PxVec3> verts; - - for (int i = 0; i < vCount; ++i) { - auto *vp = reinterpret_cast<const QVector3D *>(vd + vStride * i + m_posOffset); - verts << physx::PxVec3 { vp->x(), vp->y(), vp->z() }; - } - - const auto *convexVerts = verts.constData(); - - physx::PxConvexMeshDesc convexDesc; - convexDesc.points.count = vCount; - convexDesc.points.stride = sizeof(physx::PxVec3); - convexDesc.points.data = convexVerts; - convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX; - - const auto cooking = QPhysicsWorld::getCooking(); - if (cooking && cooking->cookConvexMesh(convexDesc, buf, &result)) { - auto size = buf.getSize(); - auto *data = buf.getData(); - physx::PxDefaultMemoryInputData input(data, size); - m_convexMesh = thePhysics->createConvexMesh(input); - qCDebug(lcQuick3dPhysics) << "Created convex mesh" << m_convexMesh << "for mesh" << this; - QCacheUtils::writeCachedConvexMesh(m_meshPath, buf); - } else { - qCWarning(lcQuick3dPhysics) << "Could not create convex mesh from" << m_meshPath; - } - - return m_convexMesh; -} - -physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMesh() -{ - - if (m_triangleMesh != nullptr) - return m_triangleMesh; - - physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics(); - if (thePhysics == nullptr) - return nullptr; - - m_triangleMesh = QCacheUtils::readCachedTriangleMesh(m_meshPath, *thePhysics); - if (m_triangleMesh != nullptr) - return m_triangleMesh; - - m_triangleMesh = QCacheUtils::readCookedTriangleMesh(m_meshPath, *thePhysics); - if (m_triangleMesh != nullptr) - return m_triangleMesh; - - loadSsgMesh(); - if (!m_ssgMesh.isValid()) - return nullptr; - - physx::PxDefaultMemoryOutputStream buf; - physx::PxTriangleMeshCookingResult::Enum result; - const int vStride = m_ssgMesh.vertexBuffer().stride; - const int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride; - const auto *vd = m_ssgMesh.vertexBuffer().data.constData(); - - const int iStride = - m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 - ? 2 - : 4; - const int iCount = m_ssgMesh.indexBuffer().data.size() / iStride; - - qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts" << iCount << "idxs"; - - physx::PxTriangleMeshDesc triangleDesc; - triangleDesc.points.count = vCount; - triangleDesc.points.stride = vStride; - triangleDesc.points.data = vd + m_posOffset; - - triangleDesc.flags = {}; //??? physx::PxMeshFlag::eFLIPNORMALS or - // physx::PxMeshFlag::e16_BIT_INDICES - triangleDesc.triangles.count = iCount / 3; - triangleDesc.triangles.stride = iStride * 3; - triangleDesc.triangles.data = m_ssgMesh.indexBuffer().data.constData(); - - const auto cooking = QPhysicsWorld::getCooking(); - if (cooking && cooking->cookTriangleMesh(triangleDesc, buf, &result)) { - auto size = buf.getSize(); - auto *data = buf.getData(); - physx::PxDefaultMemoryInputData input(data, size); - m_triangleMesh = thePhysics->createTriangleMesh(input); - qCDebug(lcQuick3dPhysics) << "Created triangle mesh" << m_triangleMesh << "for mesh" - << this; - QCacheUtils::writeCachedTriangleMesh(m_meshPath, buf); - } else { - qCWarning(lcQuick3dPhysics) << "Could not create triangle mesh from" << m_meshPath; - } - - return m_triangleMesh; -} - -void QQuick3DPhysicsMesh::loadSsgMesh() -{ - if (m_ssgMesh.isValid()) - return; - - static const char *compTypes[] = { "Null", "UnsignedInt8", "Int8", "UnsignedInt16", - "Int16", "UnsignedInt32", "Int32", "UnsignedInt64", - "Int64", "Float16", "Float32", "Float64" }; - - QFileInfo fileInfo = QFileInfo(m_meshPath); - if (fileInfo.exists()) { - QFile file(fileInfo.absoluteFilePath()); - if (file.open(QFile::ReadOnly)) - m_ssgMesh = QSSGMesh::Mesh::loadMesh(&file); - } - qCDebug(lcQuick3dPhysics) << "Loaded SSG mesh from" << m_meshPath << m_ssgMesh.isValid() - << "draw" << int(m_ssgMesh.drawMode()) << "wind" - << int(m_ssgMesh.winding()) << "subs" << m_ssgMesh.subsets().count() - << "attrs" << m_ssgMesh.vertexBuffer().entries.count() - << m_ssgMesh.vertexBuffer().data.size() << "stride" - << m_ssgMesh.vertexBuffer().stride << "verts" - << m_ssgMesh.vertexBuffer().data.size() - / m_ssgMesh.vertexBuffer().stride; - - for (auto &v : m_ssgMesh.vertexBuffer().entries) { - qCDebug(lcQuick3dPhysics) << " attr" << v.name << compTypes[int(v.componentType)] << "cc" - << v.componentCount << "offs" << v.offset; - Q_ASSERT(v.componentType == QSSGMesh::Mesh::ComponentType::Float32); - if (v.name == "attr_pos") - m_posOffset = v.offset; - } - - if (m_ssgMesh.isValid()) { - auto sub = m_ssgMesh.subsets().constFirst(); - qCDebug(lcQuick3dPhysics) << "..." << sub.name << "count" << sub.count << "bounds" - << sub.bounds.min << sub.bounds.max << "offset" << sub.offset; - } - -#if 0 // EXTRA_DEBUG - - int iStride = m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 ? 2 : 4; - int vStride = m_ssgMesh.vertexBuffer().stride; - qDebug() << "IDX" << compTypes[int(m_ssgMesh.indexBuffer().componentType)] << m_ssgMesh.indexBuffer().data.size() / iStride; - const auto ib = m_ssgMesh.indexBuffer().data; - const auto vb = m_ssgMesh.vertexBuffer().data; - - auto getPoint = [&vb, vStride, this](int idx) -> QVector3D { - auto *vp = vb.constData() + vStride * idx + m_posOffset; - return *reinterpret_cast<const QVector3D *>(vp); - return {}; - }; - - if (iStride == 2) { - - } else { - auto *ip = reinterpret_cast<const uint32_t *>(ib.data()); - int n = ib.size() / iStride; - for (int i = 0; i < qMin(50,n); i += 3) { - - qDebug() << " " << ip [i] << ip[i+1] << ip[i+2] << " --- " - << getPoint(ip[i]) << getPoint(ip[i+1]) << getPoint(ip[i+2]); - } - } -#endif - if (!m_ssgMesh.isValid()) - qCWarning(lcQuick3dPhysics) << "Could not read mesh from" << m_meshPath; -} - -QQuick3DPhysicsMesh *QQuick3DPhysicsMeshManager::getMesh(const QUrl &source, - const QObject *contextObject) -{ - const QQmlContext *context = qmlContext(contextObject); - const auto resolvedUrl = context ? context->resolvedUrl(source) : source; - const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl); - auto *mesh = meshHash.value(qmlSource); - if (!mesh) { - mesh = new QQuick3DPhysicsMesh(qmlSource); - meshHash[qmlSource] = mesh; - } - mesh->ref(); - return mesh; -} - -void QQuick3DPhysicsMeshManager::releaseMesh(QQuick3DPhysicsMesh *mesh) -{ - if (mesh->deref() == 0) { - qCDebug(lcQuick3dPhysics()) << "deleting mesh" << mesh; - erase_if(meshHash, [mesh](std::pair<const QString &, QQuick3DPhysicsMesh *&> h) { - return h.second == mesh; - }); - delete mesh; - } -} - -QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::meshHash; - /*! \qmltype ConvexMeshShape \inherits CollisionShape @@ -268,57 +30,9 @@ QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::meshHash; for details. */ -QConvexMeshShape::QConvexMeshShape() = default; - -QConvexMeshShape::~QConvexMeshShape() -{ - delete m_meshGeometry; - if (m_mesh) - QQuick3DPhysicsMeshManager::releaseMesh(m_mesh); -} - -physx::PxGeometry *QConvexMeshShape::getPhysXGeometry() -{ - if (m_dirtyPhysx || m_scaleDirty) { - updatePhysXGeometry(); - } - return m_meshGeometry; -} - -void QConvexMeshShape::updatePhysXGeometry() -{ - delete m_meshGeometry; - m_meshGeometry = nullptr; - - auto *convexMesh = m_mesh->convexMesh(); - if (!convexMesh) - return; - - auto meshScale = sceneScale(); - physx::PxMeshScale scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()), - physx::PxQuat(physx::PxIdentity)); - - m_meshGeometry = new physx::PxConvexMeshGeometry(convexMesh, scale); - m_dirtyPhysx = false; -} - -const QUrl &QConvexMeshShape::source() const +QMeshShape::MeshType QConvexMeshShape::shapeType() const { - return m_meshSource; -} - -void QConvexMeshShape::setSource(const QUrl &newSource) -{ - if (m_meshSource == newSource) - return; - m_meshSource = newSource; - m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this); - updatePhysXGeometry(); - - m_dirtyPhysx = true; - - emit needsRebuild(this); - emit sourceChanged(); + return QMeshShape::MeshType::CONVEX; } QT_END_NAMESPACE diff --git a/src/quick3dphysics/qconvexmeshshape_p.h b/src/quick3dphysics/qconvexmeshshape_p.h index 75ddad9..d48b915 100644 --- a/src/quick3dphysics/qconvexmeshshape_p.h +++ b/src/quick3dphysics/qconvexmeshshape_p.h @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef CONVEXMESHSHAPE_H @@ -15,46 +15,15 @@ // We mean it. // -#include <QtQuick3DPhysics/qtquick3dphysicsglobal.h> -#include <QtQuick3DPhysics/private/qabstractcollisionshape_p.h> -#include <QtCore/QObject> -#include <QtGui/QVector3D> -#include <QtQml/QQmlEngine> - -namespace physx { -class PxBoxGeometry; -class PxConvexMesh; -class PxConvexMeshGeometry; -} +#include "qmeshshape_p.h" QT_BEGIN_NAMESPACE -class QQuick3DPhysicsMesh; -class Q_QUICK3DPHYSICS_EXPORT QConvexMeshShape : public QAbstractCollisionShape +class Q_QUICK3DPHYSICS_EXPORT QConvexMeshShape : public QMeshShape { Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged REVISION(6, 5)) QML_NAMED_ELEMENT(ConvexMeshShape) -public: - QConvexMeshShape(); - ~QConvexMeshShape(); - - physx::PxGeometry *getPhysXGeometry() override; - - Q_REVISION(6, 5) const QUrl &source() const; - Q_REVISION(6, 5) void setSource(const QUrl &newSource); - bool isStaticShape() const override { return false; } - -signals: - Q_REVISION(6, 5) void sourceChanged(); - -private: - void updatePhysXGeometry(); - - bool m_dirtyPhysx = false; - physx::PxConvexMeshGeometry *m_meshGeometry = nullptr; - QUrl m_meshSource; - QQuick3DPhysicsMesh *m_mesh = nullptr; + virtual QMeshShape::MeshType shapeType() const override; }; QT_END_NAMESPACE diff --git a/src/quick3dphysics/qmeshshape.cpp b/src/quick3dphysics/qmeshshape.cpp new file mode 100644 index 0000000..f7d38da --- /dev/null +++ b/src/quick3dphysics/qmeshshape.cpp @@ -0,0 +1,310 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "qcacheutils_p.h" +#include "qmeshshape_p.h" + +#include <QFile> +#include <QFileInfo> +#include <QtQuick3D/QQuick3DGeometry> +#include <extensions/PxExtensionsAPI.h> + +#include "foundation/PxVec3.h" +#include "cooking/PxConvexMeshDesc.h" +#include "extensions/PxDefaultStreams.h" + +#include <QtQml/qqml.h> +#include <QtQml/QQmlFile> +#include <QtQml/qqmlcontext.h> + +#include <QtQuick3DUtils/private/qssgmesh_p.h> +#include "qmeshshape_p.h" +#include "qphysicsworld_p.h" +#include "qphysicsmeshutils_p_p.h" + +QT_BEGIN_NAMESPACE + +physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMesh() +{ + if (m_convexMesh != nullptr) + return m_convexMesh; + + physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics(); + if (thePhysics == nullptr) + return nullptr; + + m_convexMesh = QCacheUtils::readCachedConvexMesh(m_meshPath, *thePhysics); + if (m_convexMesh != nullptr) + return m_convexMesh; + + m_convexMesh = QCacheUtils::readCookedConvexMesh(m_meshPath, *thePhysics); + if (m_convexMesh != nullptr) + return m_convexMesh; + + loadSsgMesh(); + + if (!m_ssgMesh.isValid()) + return nullptr; + + physx::PxDefaultMemoryOutputStream buf; + physx::PxConvexMeshCookingResult::Enum result; + int vStride = m_ssgMesh.vertexBuffer().stride; + int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride; + const auto *vd = m_ssgMesh.vertexBuffer().data.constData(); + + qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts"; + + QVector<physx::PxVec3> verts; + + for (int i = 0; i < vCount; ++i) { + auto *vp = reinterpret_cast<const QVector3D *>(vd + vStride * i + m_posOffset); + verts << physx::PxVec3 { vp->x(), vp->y(), vp->z() }; + } + + const auto *convexVerts = verts.constData(); + + physx::PxConvexMeshDesc convexDesc; + convexDesc.points.count = vCount; + convexDesc.points.stride = sizeof(physx::PxVec3); + convexDesc.points.data = convexVerts; + convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX; + + const auto cooking = QPhysicsWorld::getCooking(); + if (cooking && cooking->cookConvexMesh(convexDesc, buf, &result)) { + auto size = buf.getSize(); + auto *data = buf.getData(); + physx::PxDefaultMemoryInputData input(data, size); + m_convexMesh = thePhysics->createConvexMesh(input); + qCDebug(lcQuick3dPhysics) << "Created convex mesh" << m_convexMesh << "for mesh" << this; + QCacheUtils::writeCachedConvexMesh(m_meshPath, buf); + } else { + qCWarning(lcQuick3dPhysics) << "Could not create convex mesh from" << m_meshPath; + } + + return m_convexMesh; +} + +physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMesh() +{ + if (m_triangleMesh != nullptr) + return m_triangleMesh; + + physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics(); + if (thePhysics == nullptr) + return nullptr; + + m_triangleMesh = QCacheUtils::readCachedTriangleMesh(m_meshPath, *thePhysics); + if (m_triangleMesh != nullptr) + return m_triangleMesh; + + m_triangleMesh = QCacheUtils::readCookedTriangleMesh(m_meshPath, *thePhysics); + if (m_triangleMesh != nullptr) + return m_triangleMesh; + + loadSsgMesh(); + if (!m_ssgMesh.isValid()) + return nullptr; + + physx::PxDefaultMemoryOutputStream buf; + physx::PxTriangleMeshCookingResult::Enum result; + const int vStride = m_ssgMesh.vertexBuffer().stride; + const int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride; + const auto *vd = m_ssgMesh.vertexBuffer().data.constData(); + + const int iStride = + m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 + ? 2 + : 4; + const int iCount = m_ssgMesh.indexBuffer().data.size() / iStride; + + qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts" << iCount << "idxs"; + + physx::PxTriangleMeshDesc triangleDesc; + triangleDesc.points.count = vCount; + triangleDesc.points.stride = vStride; + triangleDesc.points.data = vd + m_posOffset; + + triangleDesc.flags = {}; //??? physx::PxMeshFlag::eFLIPNORMALS or + // physx::PxMeshFlag::e16_BIT_INDICES + triangleDesc.triangles.count = iCount / 3; + triangleDesc.triangles.stride = iStride * 3; + triangleDesc.triangles.data = m_ssgMesh.indexBuffer().data.constData(); + + const auto cooking = QPhysicsWorld::getCooking(); + if (cooking && cooking->cookTriangleMesh(triangleDesc, buf, &result)) { + auto size = buf.getSize(); + auto *data = buf.getData(); + physx::PxDefaultMemoryInputData input(data, size); + m_triangleMesh = thePhysics->createTriangleMesh(input); + qCDebug(lcQuick3dPhysics) << "Created triangle mesh" << m_triangleMesh << "for mesh" + << this; + QCacheUtils::writeCachedTriangleMesh(m_meshPath, buf); + } else { + qCWarning(lcQuick3dPhysics) << "Could not create triangle mesh from" << m_meshPath; + } + + return m_triangleMesh; +} + +void QQuick3DPhysicsMesh::loadSsgMesh() +{ + if (m_ssgMesh.isValid()) + return; + + static const char *compTypes[] = { "Null", "UnsignedInt8", "Int8", "UnsignedInt16", + "Int16", "UnsignedInt32", "Int32", "UnsignedInt64", + "Int64", "Float16", "Float32", "Float64" }; + + QFileInfo fileInfo = QFileInfo(m_meshPath); + if (fileInfo.exists()) { + QFile file(fileInfo.absoluteFilePath()); + if (file.open(QFile::ReadOnly)) + m_ssgMesh = QSSGMesh::Mesh::loadMesh(&file); + } + qCDebug(lcQuick3dPhysics) << "Loaded SSG mesh from" << m_meshPath << m_ssgMesh.isValid() + << "draw" << int(m_ssgMesh.drawMode()) << "wind" + << int(m_ssgMesh.winding()) << "subs" << m_ssgMesh.subsets().count() + << "attrs" << m_ssgMesh.vertexBuffer().entries.count() + << m_ssgMesh.vertexBuffer().data.size() << "stride" + << m_ssgMesh.vertexBuffer().stride << "verts" + << m_ssgMesh.vertexBuffer().data.size() + / m_ssgMesh.vertexBuffer().stride; + + for (auto &v : m_ssgMesh.vertexBuffer().entries) { + qCDebug(lcQuick3dPhysics) << " attr" << v.name << compTypes[int(v.componentType)] << "cc" + << v.componentCount << "offs" << v.offset; + Q_ASSERT(v.componentType == QSSGMesh::Mesh::ComponentType::Float32); + if (v.name == "attr_pos") + m_posOffset = v.offset; + } + + if (m_ssgMesh.isValid()) { + auto sub = m_ssgMesh.subsets().constFirst(); + qCDebug(lcQuick3dPhysics) << "..." << sub.name << "count" << sub.count << "bounds" + << sub.bounds.min << sub.bounds.max << "offset" << sub.offset; + } + +#if 0 // EXTRA_DEBUG + + int iStride = m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 ? 2 : 4; + int vStride = m_ssgMesh.vertexBuffer().stride; + qDebug() << "IDX" << compTypes[int(m_ssgMesh.indexBuffer().componentType)] << m_ssgMesh.indexBuffer().data.size() / iStride; + const auto ib = m_ssgMesh.indexBuffer().data; + const auto vb = m_ssgMesh.vertexBuffer().data; + + auto getPoint = [&vb, vStride, this](int idx) -> QVector3D { + auto *vp = vb.constData() + vStride * idx + m_posOffset; + return *reinterpret_cast<const QVector3D *>(vp); + return {}; + }; + + if (iStride == 2) { + + } else { + auto *ip = reinterpret_cast<const uint32_t *>(ib.data()); + int n = ib.size() / iStride; + for (int i = 0; i < qMin(50,n); i += 3) { + + qDebug() << " " << ip [i] << ip[i+1] << ip[i+2] << " --- " + << getPoint(ip[i]) << getPoint(ip[i+1]) << getPoint(ip[i+2]); + } + } +#endif + if (!m_ssgMesh.isValid()) + qCWarning(lcQuick3dPhysics) << "Could not read mesh from" << m_meshPath; +} + +QQuick3DPhysicsMesh *QQuick3DPhysicsMeshManager::getMesh(const QUrl &source, + const QObject *contextObject) +{ + const QQmlContext *context = qmlContext(contextObject); + const auto resolvedUrl = context ? context->resolvedUrl(source) : source; + const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl); + auto *mesh = meshHash.value(qmlSource); + if (!mesh) { + mesh = new QQuick3DPhysicsMesh(qmlSource); + meshHash[qmlSource] = mesh; + } + mesh->ref(); + return mesh; +} + +void QQuick3DPhysicsMeshManager::releaseMesh(QQuick3DPhysicsMesh *mesh) +{ + if (mesh->deref() == 0) { + qCDebug(lcQuick3dPhysics()) << "deleting mesh" << mesh; + erase_if(meshHash, [mesh](std::pair<const QString &, QQuick3DPhysicsMesh *&> h) { + return h.second == mesh; + }); + delete mesh; + } +} + +QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::meshHash; + +QMeshShape::~QMeshShape() +{ + delete m_convexGeometry; + if (m_mesh) + QQuick3DPhysicsMeshManager::releaseMesh(m_mesh); +} + +physx::PxGeometry *QMeshShape::getPhysXGeometry() +{ + if (m_dirtyPhysx || m_scaleDirty) + updatePhysXGeometry(); + if (shapeType() == MeshType::CONVEX) + return m_convexGeometry; + if (shapeType() == MeshType::TRIANGLE) + return m_triangleGeometry; + + Q_UNREACHABLE_RETURN(nullptr); +} + +void QMeshShape::updatePhysXGeometry() +{ + delete m_convexGeometry; + delete m_triangleGeometry; + m_convexGeometry = nullptr; + m_triangleGeometry = nullptr; + + if (!m_mesh) + return; + + auto *convexMesh = shapeType() == MeshType::CONVEX ? m_mesh->convexMesh() : nullptr; + auto *triangleMesh = shapeType() == MeshType::TRIANGLE ? m_mesh->triangleMesh() : nullptr; + if (!convexMesh && !triangleMesh) + return; + + auto meshScale = sceneScale(); + physx::PxMeshScale scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()), + physx::PxQuat(physx::PxIdentity)); + + if (convexMesh) + m_convexGeometry = new physx::PxConvexMeshGeometry(convexMesh, scale); + if (triangleMesh) + m_triangleGeometry = new physx::PxTriangleMeshGeometry(triangleMesh, scale); + + m_dirtyPhysx = false; +} + +const QUrl &QMeshShape::source() const +{ + return m_meshSource; +} + +void QMeshShape::setSource(const QUrl &newSource) +{ + if (m_meshSource == newSource) + return; + m_meshSource = newSource; + m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this); + updatePhysXGeometry(); + + m_dirtyPhysx = true; + + emit needsRebuild(this); + emit sourceChanged(); +} + +QT_END_NAMESPACE diff --git a/src/quick3dphysics/qmeshshape_p.h b/src/quick3dphysics/qmeshshape_p.h new file mode 100644 index 0000000..a903390 --- /dev/null +++ b/src/quick3dphysics/qmeshshape_p.h @@ -0,0 +1,69 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MESHSHAPE_H +#define MESHSHAPE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuick3DPhysics/qtquick3dphysicsglobal.h> +#include <QtQuick3DPhysics/private/qabstractcollisionshape_p.h> +#include <QtCore/QObject> +#include <QtGui/QVector3D> +#include <QtQml/QQmlEngine> + +namespace physx { +class PxBoxGeometry; +class PxConvexMesh; +class PxConvexMeshGeometry; +class PxTriangleMesh; +class PxTriangleMeshGeometry; +} + +QT_BEGIN_NAMESPACE +class QQuick3DPhysicsMesh; + +class Q_QUICK3DPHYSICS_EXPORT QMeshShape : public QAbstractCollisionShape +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged REVISION(6, 5)) + QML_NAMED_ELEMENT(MeshShape) + QML_UNCREATABLE("abstract interface") + +public: + ~QMeshShape(); + + enum class MeshType { TRIANGLE, CONVEX }; + virtual MeshType shapeType() const = 0; + + physx::PxGeometry *getPhysXGeometry() override; + + Q_REVISION(6, 5) const QUrl &source() const; + Q_REVISION(6, 5) void setSource(const QUrl &newSource); + bool isStaticShape() const override { return false; } + +signals: + Q_REVISION(6, 5) void sourceChanged(); + +private: + void updatePhysXGeometry(); + + bool m_dirtyPhysx = false; + physx::PxConvexMeshGeometry *m_convexGeometry = nullptr; + physx::PxTriangleMeshGeometry *m_triangleGeometry = nullptr; + QUrl m_meshSource; + QQuick3DPhysicsMesh *m_mesh = nullptr; +}; + +QT_END_NAMESPACE + +#endif // MESHSHAPE_H diff --git a/src/quick3dphysics/qtrianglemeshshape.cpp b/src/quick3dphysics/qtrianglemeshshape.cpp index f804d48..64f86e1 100644 --- a/src/quick3dphysics/qtrianglemeshshape.cpp +++ b/src/quick3dphysics/qtrianglemeshshape.cpp @@ -1,19 +1,8 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "qtrianglemeshshape_p.h" -#include <QtQuick3D/QQuick3DGeometry> -#include <extensions/PxExtensionsAPI.h> - -#include "qphysicsmeshutils_p_p.h" - -//######################################################################################## -// NOTE: -// Triangle mesh, heightfield or plane geometry shapes configured as eSIMULATION_SHAPE are -// not supported for non-kinematic PxRigidDynamic instances. -//######################################################################################## - QT_BEGIN_NAMESPACE /*! @@ -42,58 +31,9 @@ QT_BEGIN_NAMESPACE for details. */ -QTriangleMeshShape::QTriangleMeshShape() = default; - -QTriangleMeshShape::~QTriangleMeshShape() +QMeshShape::MeshType QTriangleMeshShape::shapeType() const { - delete m_meshGeometry; - if (m_mesh) - QQuick3DPhysicsMeshManager::releaseMesh(m_mesh); -} - -physx::PxGeometry *QTriangleMeshShape::getPhysXGeometry() -{ - if (m_dirtyPhysx || m_scaleDirty) { - updatePhysXGeometry(); - } - return m_meshGeometry; -} - -void QTriangleMeshShape::updatePhysXGeometry() -{ - delete m_meshGeometry; - m_meshGeometry = nullptr; - - if (!m_mesh) - return; - auto *triangleMesh = m_mesh->triangleMesh(); - if (!triangleMesh) - return; - - auto meshScale = sceneScale(); - physx::PxMeshScale scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()), - physx::PxQuat(physx::PxIdentity)); - - m_meshGeometry = new physx::PxTriangleMeshGeometry(triangleMesh, scale); - m_dirtyPhysx = false; -} - -const QUrl &QTriangleMeshShape::source() const -{ - return m_meshSource; -} - -void QTriangleMeshShape::setSource(const QUrl &newSource) -{ - if (m_meshSource == newSource) - return; - m_meshSource = newSource; - m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this); - - updatePhysXGeometry(); - - emit needsRebuild(this); - emit sourceChanged(); + return QMeshShape::MeshType::TRIANGLE; } QT_END_NAMESPACE diff --git a/src/quick3dphysics/qtrianglemeshshape_p.h b/src/quick3dphysics/qtrianglemeshshape_p.h index a974e50..1fac3f2 100644 --- a/src/quick3dphysics/qtrianglemeshshape_p.h +++ b/src/quick3dphysics/qtrianglemeshshape_p.h @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef TRIANGLEMESHSHAPE_H @@ -15,47 +15,15 @@ // We mean it. // -#include <QtQuick3DPhysics/qtquick3dphysicsglobal.h> -#include <QtQuick3DPhysics/private/qabstractcollisionshape_p.h> -#include <QtCore/QObject> -#include <QtGui/QVector3D> -#include <QtQml/QQmlEngine> - -namespace physx { -class PxBoxGeometry; -class PxTriangleMesh; -class PxTriangleMeshGeometry; -} +#include "qmeshshape_p.h" QT_BEGIN_NAMESPACE -class QQuick3DPhysicsMesh; -class Q_QUICK3DPHYSICS_EXPORT QTriangleMeshShape : public QAbstractCollisionShape +class Q_QUICK3DPHYSICS_EXPORT QTriangleMeshShape : public QMeshShape { Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged REVISION(6, 5)) - QML_NAMED_ELEMENT(TriangleMeshShape) -public: - QTriangleMeshShape(); - ~QTriangleMeshShape(); - - physx::PxGeometry *getPhysXGeometry() override; - Q_REVISION(6, 5) const QUrl &source() const; - Q_REVISION(6, 5) void setSource(const QUrl &newSource); - bool isStaticShape() const override { return true; } - -signals: - Q_REVISION(6, 5) void sourceChanged(); - -private: - void updatePhysXGeometry(); - - bool m_dirtyPhysx = false; - QUrl m_meshSource; - QQuick3DPhysicsMesh *m_mesh = nullptr; - - physx::PxTriangleMeshGeometry *m_meshGeometry = nullptr; + virtual QMeshShape::MeshType shapeType() const override; }; QT_END_NAMESPACE |