9#include <QtQuick3D/QQuick3DGeometry>
10#include <extensions/PxExtensionsAPI.h>
12#include "foundation/PxVec3.h"
13#include "cooking/PxConvexMeshDesc.h"
14#include "extensions/PxDefaultStreams.h"
16#include <QtQml/qqml.h>
17#include <QtQml/QQmlFile>
18#include <QtQml/qqmlcontext.h>
20#include <QtQuick3DUtils/private/qssgmesh_p.h>
21#include <QtQuick3D/QQuick3DGeometry>
35 if (attr.semantic == semantic)
45 if (m_convexMesh !=
nullptr)
48 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
49 if (thePhysics ==
nullptr)
53 return convexMeshGeometrySource();
55 return convexMeshQmlSource();
61 if (m_triangleMesh !=
nullptr)
62 return m_triangleMesh;
64 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
65 if (thePhysics ==
nullptr)
69 return triangleMeshGeometrySource();
71 return triangleMeshQmlSource();
75physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMeshQmlSource()
77 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
80 if (m_convexMesh !=
nullptr)
84 if (m_convexMesh !=
nullptr)
95 qCDebug(lcQuick3dPhysics) <<
"prepare cooking" << vCount <<
"verts";
97 physx::PxConvexMeshDesc convexDesc;
98 convexDesc.points.count = vCount;
99 convexDesc.points.stride = vStride;
101 convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
106 physx::PxDefaultMemoryOutputStream
buf;
107 physx::PxConvexMeshCookingResult::Enum
result;
108 const auto cooking = QPhysicsWorld::getCooking();
109 if (cooking && cooking->cookConvexMesh(convexDesc,
buf, &
result)) {
113 m_convexMesh = thePhysics->createConvexMesh(
input);
114 qCDebug(lcQuick3dPhysics) <<
"Created convex mesh" << m_convexMesh <<
"for mesh" <<
this;
117 qCWarning(lcQuick3dPhysics) <<
"Could not create convex mesh from" << m_meshPath;
123physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMeshGeometrySource()
125 auto vertexBuffer = m_meshGeometry->
vertexData();
128 qWarning() <<
"QQuick3DPhysicsMesh: Invalid geometry primitive type, must be Triangles. ";
132 if (!vertexBuffer.size()) {
133 qWarning() <<
"QQuick3DPhysicsMesh: Invalid geometry, vertexData is empty. ";
137 const auto vertexAttribute =
142 const auto numVertices = vertexBuffer.size() /
stride;
144 physx::PxConvexMeshDesc convexDesc;
145 convexDesc.points.count = numVertices;
146 convexDesc.points.stride =
stride;
147 convexDesc.points.data = vertexBuffer.constData() + vertexAttribute.offset;
148 convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
153 const auto cooking = QPhysicsWorld::getCooking();
154 physx::PxDefaultMemoryOutputStream
buf;
155 physx::PxConvexMeshCookingResult::Enum
result;
156 if (cooking && cooking->cookConvexMesh(convexDesc,
buf, &
result)) {
160 m_convexMesh = QPhysicsWorld::getPhysics()->createConvexMesh(
input);
161 qCDebug(lcQuick3dPhysics) <<
"Created convex mesh" << m_convexMesh <<
"for mesh" <<
this;
163 qCWarning(lcQuick3dPhysics) <<
"Could not create convex mesh for" <<
this;
169physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMeshQmlSource()
171 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
174 if (m_triangleMesh !=
nullptr)
175 return m_triangleMesh;
178 if (m_triangleMesh !=
nullptr)
179 return m_triangleMesh;
187 const int posOffset = m_posOffset;
189 const auto numVertices = vertexBuffer.size() /
stride;
191 physx::PxTriangleMeshDesc triangleDesc;
192 triangleDesc.points.count = numVertices;
193 triangleDesc.points.stride =
stride;
194 triangleDesc.points.data = vertexBuffer.constData() + posOffset;
197 if (indexBuffer.size()) {
198 const bool u16IndexType =
202 == QSSGMesh::Mesh::ComponentType::UnsignedInt16
204 == QSSGMesh::Mesh::ComponentType::UnsignedInt32);
206 triangleDesc.triangles.data = indexBuffer.constData();
208 triangleDesc.flags.set(physx::PxMeshFlag::e16_BIT_INDICES);
209 triangleDesc.triangles.stride =
sizeof(
quint16) * 3;
211 triangleDesc.triangles.stride =
sizeof(
quint32) * 3;
213 triangleDesc.triangles.count = indexBuffer.size() / triangleDesc.triangles.stride;
216 physx::PxDefaultMemoryOutputStream
buf;
217 physx::PxTriangleMeshCookingResult::Enum
result;
218 const auto cooking = QPhysicsWorld::getCooking();
219 if (cooking && cooking->cookTriangleMesh(triangleDesc,
buf, &
result)) {
223 m_triangleMesh = thePhysics->createTriangleMesh(
input);
224 qCDebug(lcQuick3dPhysics) <<
"Created triangle mesh" << m_triangleMesh <<
"for mesh"
228 qCWarning(lcQuick3dPhysics) <<
"Could not create triangle mesh from" << m_meshPath;
231 return m_triangleMesh;
234physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMeshGeometrySource()
236 auto vertexBuffer = m_meshGeometry->
vertexData();
239 qWarning() <<
"QQuick3DPhysicsMesh: Invalid geometry primitive type, must be Triangles. ";
243 if (!vertexBuffer.size()) {
244 qWarning() <<
"QQuick3DPhysicsMesh: Invalid geometry, vertexData is empty. ";
248 const auto vertexAttribute =
252 const int posOffset = vertexAttribute.offset;
254 const auto numVertices = vertexBuffer.size() /
stride;
256 physx::PxTriangleMeshDesc triangleDesc;
257 triangleDesc.points.count = numVertices;
258 triangleDesc.points.stride =
stride;
259 triangleDesc.points.data = vertexBuffer.constData() + posOffset;
261 auto indexBuffer = m_meshGeometry->
indexData();
262 if (indexBuffer.size()) {
263 const auto indexAttribute =
265 const bool u16IndexType =
271 triangleDesc.triangles.data = indexBuffer.constData();
273 triangleDesc.flags.set(physx::PxMeshFlag::e16_BIT_INDICES);
274 triangleDesc.triangles.stride =
sizeof(
quint16) * 3;
276 triangleDesc.triangles.stride =
sizeof(
quint32) * 3;
278 triangleDesc.triangles.count = indexBuffer.size() / triangleDesc.triangles.stride;
281 physx::PxDefaultMemoryOutputStream
buf;
282 physx::PxTriangleMeshCookingResult::Enum
result;
283 const auto cooking = QPhysicsWorld::getCooking();
284 if (cooking && cooking->cookTriangleMesh(triangleDesc,
buf, &
result)) {
288 m_triangleMesh = QPhysicsWorld::getPhysics()->createTriangleMesh(
input);
289 qCDebug(lcQuick3dPhysics) <<
"Created triangle mesh" << m_triangleMesh <<
"for mesh"
292 qCWarning(lcQuick3dPhysics) <<
"Could not create triangle mesh for" <<
this;
295 return m_triangleMesh;
298void QQuick3DPhysicsMesh::loadSsgMesh()
303 static const char *compTypes[] = {
"Null",
"UnsignedInt8",
"Int8",
"UnsignedInt16",
304 "Int16",
"UnsignedInt32",
"Int32",
"UnsignedInt64",
305 "Int64",
"Float16",
"Float32",
"Float64" };
313 qCDebug(lcQuick3dPhysics) <<
"Loaded SSG mesh from" << m_meshPath << m_ssgMesh.
isValid()
314 <<
"draw" << int(m_ssgMesh.
drawMode()) <<
"wind"
315 << int(m_ssgMesh.
winding()) <<
"subs" << m_ssgMesh.
subsets().count()
322 for (
auto &
v : m_ssgMesh.vertexBuffer().entries) {
323 qCDebug(lcQuick3dPhysics) <<
" attr" <<
v.name << compTypes[int(
v.componentType)] <<
"cc"
324 <<
v.componentCount <<
"offs" <<
v.offset;
325 Q_ASSERT(
v.componentType == QSSGMesh::Mesh::ComponentType::Float32);
326 if (
v.name ==
"attr_pos")
327 m_posOffset =
v.offset;
332 qCDebug(lcQuick3dPhysics) <<
"..." <<
sub.name <<
"count" <<
sub.count <<
"bounds"
333 <<
sub.bounds.min <<
sub.bounds.max <<
"offset" <<
sub.offset;
344 auto getPoint = [&vb, vStride,
this](
int idx) ->
QVector3D {
345 auto *vp = vb.constData() + vStride * idx + m_posOffset;
346 return *
reinterpret_cast<const QVector3D *
>(vp);
353 auto *ip =
reinterpret_cast<const uint32_t *
>(ib.data());
354 int n = ib.size() / iStride;
355 for (
int i = 0;
i <
qMin(50,
n);
i += 3) {
357 qDebug() <<
" " << ip [
i] << ip[
i+1] << ip[
i+2] <<
" --- "
358 << getPoint(ip[
i]) << getPoint(ip[
i+1]) << getPoint(ip[
i+2]);
363 qCWarning(lcQuick3dPhysics) <<
"Could not read mesh from" << m_meshPath;
372 auto *mesh = sourceMeshHash.value(qmlSource);
375 sourceMeshHash[qmlSource] = mesh;
383 auto *mesh = geometryMeshHash.value(
source);
386 geometryMeshHash.insert(
source, mesh);
394 if (mesh ==
nullptr || mesh->
deref() > 0)
397 qCDebug(lcQuick3dPhysics()) <<
"deleting mesh" << mesh;
398 erase_if(sourceMeshHash, [mesh](std::pair<const QString &, QQuick3DPhysicsMesh *&>
h) {
399 return h.second == mesh;
401 erase_if(geometryMeshHash, [mesh](std::pair<QQuick3DGeometry *, QQuick3DPhysicsMesh *&>
h) {
402 return h.second == mesh;
407QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::sourceMeshHash;
408QHash<QQuick3DGeometry *, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::geometryMeshHash;
414 delete m_convexGeometry;
422 updatePhysXGeometry();
424 return m_convexGeometry;
426 return m_triangleGeometry;
428 Q_UNREACHABLE_RETURN(
nullptr);
431void QMeshShape::updatePhysXGeometry()
433 delete m_convexGeometry;
434 delete m_triangleGeometry;
435 m_convexGeometry =
nullptr;
436 m_triangleGeometry =
nullptr;
443 if (!convexMesh && !triangleMesh)
447 physx::PxMeshScale
scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()),
448 physx::PxQuat(physx::PxIdentity));
451 m_convexGeometry =
new physx::PxConvexMeshGeometry(convexMesh,
scale);
453 m_triangleGeometry =
new physx::PxTriangleMeshGeometry(triangleMesh,
scale);
455 m_dirtyPhysx =
false;
463void QMeshShape::setSource(
const QUrl &newSource)
465 if (m_meshSource == newSource)
467 m_meshSource = newSource;
471 if (m_geometry ==
nullptr) {
477 if (m_geometry ==
nullptr && !newSource.isEmpty())
480 updatePhysXGeometry();
484 emit sourceChanged();
494 if (m_geometry == newGeometry)
499 m_geometry = newGeometry;
501 if (m_geometry !=
nullptr) {
503 connect(m_geometry, &QQuick3DGeometry::geometryChanged,
this,
504 &QMeshShape::geometryContentChanged);
510 if (m_geometry !=
nullptr)
512 else if (!m_meshSource.
isEmpty())
515 updatePhysXGeometry();
518 emit geometryChanged();
521void QMeshShape::geometryDestroyed(
QObject *geometry)
525 setGeometry(
nullptr);
528void QMeshShape::geometryContentChanged()
534 updatePhysXGeometry();
void needsRebuild(QObject *)
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
QString absoluteFilePath() const
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
physx::PxGeometry * getPhysXGeometry() override
virtual MeshType shapeType() const =0
QQuick3DGeometry * geometry
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
The QQmlContext class defines a context within a QML engine.
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
\qmltype Geometry \inherits Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DGeometry
Attribute::Semantic int int stride
Returns the byte stride of the vertex buffer.
int attributeCount() const
Returns the number of attributes defined for this geometry.
PrimitiveType primitiveType() const
Returns the primitive type used when rendering.
Attribute attribute(int index) const
Returns attribute definition number index.
QByteArray vertexData() const
Returns the vertex buffer data set by setVertexData.
QByteArray indexData() const
Returns the index buffer data.
static void releaseMesh(QQuick3DPhysicsMesh *mesh)
static QQuick3DPhysicsMesh * getMesh(const QUrl &source, const QObject *contextObject)
physx::PxTriangleMesh * triangleMesh()
physx::PxConvexMesh * convexMesh()
static Mesh loadMesh(QIODevice *device, quint32 id=0)
VertexBuffer vertexBuffer() const
IndexBuffer indexBuffer() const
QVector< Subset > subsets() const
DrawMode drawMode() const
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
The QVector3D class represents a vector or vertex in 3D space.
void writeCachedConvexMesh(const QString &filePath, physx::PxDefaultMemoryOutputStream &buf)
void writeCachedTriangleMesh(const QString &filePath, physx::PxDefaultMemoryOutputStream &buf)
physx::PxTriangleMesh * readCachedTriangleMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxConvexMesh * readCookedConvexMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxTriangleMesh * readCookedTriangleMesh(const QString &filePath, physx::PxPhysics &physics)
physx::PxConvexMesh * readCachedConvexMesh(const QString &filePath, physx::PxPhysics &physics)
Combined button and popup list for selecting options.
qsizetype erase_if(QByteArray &ba, Predicate pred)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter * sub
#define qCWarning(category,...)
#define qCDebug(category,...)
static QT_BEGIN_NAMESPACE QQuick3DGeometry::Attribute attributeBySemantic(const QQuick3DGeometry *geometry, QQuick3DGeometry::Attribute::Semantic semantic)
constexpr const T & qMin(const T &a, const T &b)
GLsizei const GLfloat * v
[13]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const void GLsizei GLsizei stride
GLenum GLuint GLenum GLsizei const GLchar * buf
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLenum input
QQmlContext * qmlContext(const QObject *obj)
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
ComponentType componentType
QVector< VertexBufferEntry > entries