Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qmeshshape.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qcacheutils_p.h"
5#include "qmeshshape_p.h"
6
7#include <QFile>
8#include <QFileInfo>
9#include <QtQuick3D/QQuick3DGeometry>
10#include <extensions/PxExtensionsAPI.h>
11
12#include "foundation/PxVec3.h"
13#include "cooking/PxConvexMeshDesc.h"
14#include "extensions/PxDefaultStreams.h"
15
16#include <QtQml/qqml.h>
17#include <QtQml/QQmlFile>
18#include <QtQml/qqmlcontext.h>
19
20#include <QtQuick3DUtils/private/qssgmesh_p.h>
21#include <QtQuick3D/QQuick3DGeometry>
22
23#include "qmeshshape_p.h"
24#include "qphysicsworld_p.h"
26
28
32{
33 for (int i = 0; i < geometry->attributeCount(); i++) {
34 const auto attr = geometry->attribute(i);
35 if (attr.semantic == semantic)
36 return attr;
37 }
38
39 Q_UNREACHABLE();
41};
42
43physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMesh()
44{
45 if (m_convexMesh != nullptr)
46 return m_convexMesh;
47
48 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
49 if (thePhysics == nullptr)
50 return nullptr;
51
52 if (m_meshGeometry)
53 return convexMeshGeometrySource();
54 if (!m_meshPath.isEmpty())
55 return convexMeshQmlSource();
56 return nullptr;
57}
58
59physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMesh()
60{
61 if (m_triangleMesh != nullptr)
62 return m_triangleMesh;
63
64 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
65 if (thePhysics == nullptr)
66 return nullptr;
67
68 if (m_meshGeometry)
69 return triangleMeshGeometrySource();
70 if (!m_meshPath.isEmpty())
71 return triangleMeshQmlSource();
72 return nullptr;
73}
74
75physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMeshQmlSource()
76{
77 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
78
79 m_convexMesh = QCacheUtils::readCachedConvexMesh(m_meshPath, *thePhysics);
80 if (m_convexMesh != nullptr)
81 return m_convexMesh;
82
83 m_convexMesh = QCacheUtils::readCookedConvexMesh(m_meshPath, *thePhysics);
84 if (m_convexMesh != nullptr)
85 return m_convexMesh;
86
87 loadSsgMesh();
88
89 if (!m_ssgMesh.isValid())
90 return nullptr;
91
92 const int vStride = m_ssgMesh.vertexBuffer().stride;
93 const int vCount = m_ssgMesh.vertexBuffer().data.size() / vStride;
94
95 qCDebug(lcQuick3dPhysics) << "prepare cooking" << vCount << "verts";
96
97 physx::PxConvexMeshDesc convexDesc;
98 convexDesc.points.count = vCount;
99 convexDesc.points.stride = vStride;
100 convexDesc.points.data = m_ssgMesh.vertexBuffer().data.constData() + m_posOffset;
101 convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;
102
103 // NOTE: Since we are making a mesh for the convex hull and are only
104 // interested in the positions we can Skip the index array.
105
106 physx::PxDefaultMemoryOutputStream buf;
107 physx::PxConvexMeshCookingResult::Enum result;
108 const auto cooking = QPhysicsWorld::getCooking();
109 if (cooking && cooking->cookConvexMesh(convexDesc, buf, &result)) {
110 auto size = buf.getSize();
111 auto *data = buf.getData();
112 physx::PxDefaultMemoryInputData input(data, size);
113 m_convexMesh = thePhysics->createConvexMesh(input);
114 qCDebug(lcQuick3dPhysics) << "Created convex mesh" << m_convexMesh << "for mesh" << this;
116 } else {
117 qCWarning(lcQuick3dPhysics) << "Could not create convex mesh from" << m_meshPath;
118 }
119
120 return m_convexMesh;
121}
122
123physx::PxConvexMesh *QQuick3DPhysicsMesh::convexMeshGeometrySource()
124{
125 auto vertexBuffer = m_meshGeometry->vertexData();
126
128 qWarning() << "QQuick3DPhysicsMesh: Invalid geometry primitive type, must be Triangles. ";
129 return nullptr;
130 }
131
132 if (!vertexBuffer.size()) {
133 qWarning() << "QQuick3DPhysicsMesh: Invalid geometry, vertexData is empty. ";
134 return nullptr;
135 }
136
137 const auto vertexAttribute =
139 Q_ASSERT(vertexAttribute.componentType == QQuick3DGeometry::Attribute::F32Type);
140
141 const auto stride = m_meshGeometry->stride();
142 const auto numVertices = vertexBuffer.size() / stride;
143
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;
149
150 // NOTE: Since we are making a mesh for the convex hull and are only
151 // interested in the positions we can Skip the index array.
152
153 const auto cooking = QPhysicsWorld::getCooking();
154 physx::PxDefaultMemoryOutputStream buf;
155 physx::PxConvexMeshCookingResult::Enum result;
156 if (cooking && cooking->cookConvexMesh(convexDesc, buf, &result)) {
157 auto size = buf.getSize();
158 auto *data = buf.getData();
159 physx::PxDefaultMemoryInputData input(data, size);
160 m_convexMesh = QPhysicsWorld::getPhysics()->createConvexMesh(input);
161 qCDebug(lcQuick3dPhysics) << "Created convex mesh" << m_convexMesh << "for mesh" << this;
162 } else {
163 qCWarning(lcQuick3dPhysics) << "Could not create convex mesh for" << this;
164 }
165
166 return m_convexMesh;
167}
168
169physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMeshQmlSource()
170{
171 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
172
173 m_triangleMesh = QCacheUtils::readCachedTriangleMesh(m_meshPath, *thePhysics);
174 if (m_triangleMesh != nullptr)
175 return m_triangleMesh;
176
177 m_triangleMesh = QCacheUtils::readCookedTriangleMesh(m_meshPath, *thePhysics);
178 if (m_triangleMesh != nullptr)
179 return m_triangleMesh;
180
181 loadSsgMesh();
182 if (!m_ssgMesh.isValid())
183 return nullptr;
184
185 auto vertexBuffer = m_ssgMesh.vertexBuffer().data;
186
187 const int posOffset = m_posOffset;
188 const auto stride = m_ssgMesh.vertexBuffer().stride;
189 const auto numVertices = vertexBuffer.size() / stride;
190
191 physx::PxTriangleMeshDesc triangleDesc;
192 triangleDesc.points.count = numVertices;
193 triangleDesc.points.stride = stride;
194 triangleDesc.points.data = vertexBuffer.constData() + posOffset;
195
196 auto indexBuffer = m_ssgMesh.indexBuffer().data;
197 if (indexBuffer.size()) {
198 const bool u16IndexType =
199 m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16;
200
202 == QSSGMesh::Mesh::ComponentType::UnsignedInt16
203 || m_ssgMesh.indexBuffer().componentType
204 == QSSGMesh::Mesh::ComponentType::UnsignedInt32);
205
206 triangleDesc.triangles.data = indexBuffer.constData();
207 if (u16IndexType) {
208 triangleDesc.flags.set(physx::PxMeshFlag::e16_BIT_INDICES);
209 triangleDesc.triangles.stride = sizeof(quint16) * 3;
210 } else {
211 triangleDesc.triangles.stride = sizeof(quint32) * 3;
212 }
213 triangleDesc.triangles.count = indexBuffer.size() / triangleDesc.triangles.stride;
214 }
215
216 physx::PxDefaultMemoryOutputStream buf;
217 physx::PxTriangleMeshCookingResult::Enum result;
218 const auto cooking = QPhysicsWorld::getCooking();
219 if (cooking && cooking->cookTriangleMesh(triangleDesc, buf, &result)) {
220 auto size = buf.getSize();
221 auto *data = buf.getData();
222 physx::PxDefaultMemoryInputData input(data, size);
223 m_triangleMesh = thePhysics->createTriangleMesh(input);
224 qCDebug(lcQuick3dPhysics) << "Created triangle mesh" << m_triangleMesh << "for mesh"
225 << this;
227 } else {
228 qCWarning(lcQuick3dPhysics) << "Could not create triangle mesh from" << m_meshPath;
229 }
230
231 return m_triangleMesh;
232}
233
234physx::PxTriangleMesh *QQuick3DPhysicsMesh::triangleMeshGeometrySource()
235{
236 auto vertexBuffer = m_meshGeometry->vertexData();
237
239 qWarning() << "QQuick3DPhysicsMesh: Invalid geometry primitive type, must be Triangles. ";
240 return nullptr;
241 }
242
243 if (!vertexBuffer.size()) {
244 qWarning() << "QQuick3DPhysicsMesh: Invalid geometry, vertexData is empty. ";
245 return nullptr;
246 }
247
248 const auto vertexAttribute =
250 Q_ASSERT(vertexAttribute.componentType == QQuick3DGeometry::Attribute::F32Type);
251
252 const int posOffset = vertexAttribute.offset;
253 const auto stride = m_meshGeometry->stride();
254 const auto numVertices = vertexBuffer.size() / stride;
255
256 physx::PxTriangleMeshDesc triangleDesc;
257 triangleDesc.points.count = numVertices;
258 triangleDesc.points.stride = stride;
259 triangleDesc.points.data = vertexBuffer.constData() + posOffset;
260
261 auto indexBuffer = m_meshGeometry->indexData();
262 if (indexBuffer.size()) {
263 const auto indexAttribute =
265 const bool u16IndexType =
266 indexAttribute.componentType == QQuick3DGeometry::Attribute::U16Type;
267
268 Q_ASSERT(indexAttribute.componentType == QQuick3DGeometry::Attribute::U16Type
269 || indexAttribute.componentType == QQuick3DGeometry::Attribute::U32Type);
270
271 triangleDesc.triangles.data = indexBuffer.constData();
272 if (u16IndexType) {
273 triangleDesc.flags.set(physx::PxMeshFlag::e16_BIT_INDICES);
274 triangleDesc.triangles.stride = sizeof(quint16) * 3;
275 } else {
276 triangleDesc.triangles.stride = sizeof(quint32) * 3;
277 }
278 triangleDesc.triangles.count = indexBuffer.size() / triangleDesc.triangles.stride;
279 }
280
281 physx::PxDefaultMemoryOutputStream buf;
282 physx::PxTriangleMeshCookingResult::Enum result;
283 const auto cooking = QPhysicsWorld::getCooking();
284 if (cooking && cooking->cookTriangleMesh(triangleDesc, buf, &result)) {
285 auto size = buf.getSize();
286 auto *data = buf.getData();
287 physx::PxDefaultMemoryInputData input(data, size);
288 m_triangleMesh = QPhysicsWorld::getPhysics()->createTriangleMesh(input);
289 qCDebug(lcQuick3dPhysics) << "Created triangle mesh" << m_triangleMesh << "for mesh"
290 << this;
291 } else {
292 qCWarning(lcQuick3dPhysics) << "Could not create triangle mesh for" << this;
293 }
294
295 return m_triangleMesh;
296}
297
298void QQuick3DPhysicsMesh::loadSsgMesh()
299{
300 if (m_ssgMesh.isValid())
301 return;
302
303 static const char *compTypes[] = { "Null", "UnsignedInt8", "Int8", "UnsignedInt16",
304 "Int16", "UnsignedInt32", "Int32", "UnsignedInt64",
305 "Int64", "Float16", "Float32", "Float64" };
306
307 QFileInfo fileInfo = QFileInfo(m_meshPath);
308 if (fileInfo.exists()) {
309 QFile file(fileInfo.absoluteFilePath());
311 m_ssgMesh = QSSGMesh::Mesh::loadMesh(&file);
312 }
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()
316 << "attrs" << m_ssgMesh.vertexBuffer().entries.count()
317 << m_ssgMesh.vertexBuffer().data.size() << "stride"
318 << m_ssgMesh.vertexBuffer().stride << "verts"
319 << m_ssgMesh.vertexBuffer().data.size()
320 / m_ssgMesh.vertexBuffer().stride;
321
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;
328 }
329
330 if (m_ssgMesh.isValid()) {
331 auto sub = m_ssgMesh.subsets().constFirst();
332 qCDebug(lcQuick3dPhysics) << "..." << sub.name << "count" << sub.count << "bounds"
333 << sub.bounds.min << sub.bounds.max << "offset" << sub.offset;
334 }
335
336#if 0 // EXTRA_DEBUG
337
338 int iStride = m_ssgMesh.indexBuffer().componentType == QSSGMesh::Mesh::ComponentType::UnsignedInt16 ? 2 : 4;
339 int vStride = m_ssgMesh.vertexBuffer().stride;
340 qDebug() << "IDX" << compTypes[int(m_ssgMesh.indexBuffer().componentType)] << m_ssgMesh.indexBuffer().data.size() / iStride;
341 const auto ib = m_ssgMesh.indexBuffer().data;
342 const auto vb = m_ssgMesh.vertexBuffer().data;
343
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);
347 return {};
348 };
349
350 if (iStride == 2) {
351
352 } else {
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) {
356
357 qDebug() << " " << ip [i] << ip[i+1] << ip[i+2] << " --- "
358 << getPoint(ip[i]) << getPoint(ip[i+1]) << getPoint(ip[i+2]);
359 }
360 }
361#endif
362 if (!m_ssgMesh.isValid())
363 qCWarning(lcQuick3dPhysics) << "Could not read mesh from" << m_meshPath;
364}
365
367 const QObject *contextObject)
368{
369 const QQmlContext *context = qmlContext(contextObject);
370 const auto resolvedUrl = context ? context->resolvedUrl(source) : source;
371 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
372 auto *mesh = sourceMeshHash.value(qmlSource);
373 if (!mesh) {
374 mesh = new QQuick3DPhysicsMesh(qmlSource);
375 sourceMeshHash[qmlSource] = mesh;
376 }
377 mesh->ref();
378 return mesh;
379}
380
382{
383 auto *mesh = geometryMeshHash.value(source);
384 if (!mesh) {
385 mesh = new QQuick3DPhysicsMesh(source);
386 geometryMeshHash.insert(source, mesh);
387 }
388 mesh->ref();
389 return mesh;
390}
391
393{
394 if (mesh == nullptr || mesh->deref() > 0)
395 return;
396
397 qCDebug(lcQuick3dPhysics()) << "deleting mesh" << mesh;
398 erase_if(sourceMeshHash, [mesh](std::pair<const QString &, QQuick3DPhysicsMesh *&> h) {
399 return h.second == mesh;
400 });
401 erase_if(geometryMeshHash, [mesh](std::pair<QQuick3DGeometry *, QQuick3DPhysicsMesh *&> h) {
402 return h.second == mesh;
403 });
404 delete mesh;
405}
406
407QHash<QString, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::sourceMeshHash;
408QHash<QQuick3DGeometry *, QQuick3DPhysicsMesh *> QQuick3DPhysicsMeshManager::geometryMeshHash;
409
411
413{
414 delete m_convexGeometry;
415 if (m_mesh)
417}
418
420{
421 if (m_dirtyPhysx || m_scaleDirty)
422 updatePhysXGeometry();
424 return m_convexGeometry;
426 return m_triangleGeometry;
427
428 Q_UNREACHABLE_RETURN(nullptr);
429}
430
431void QMeshShape::updatePhysXGeometry()
432{
433 delete m_convexGeometry;
434 delete m_triangleGeometry;
435 m_convexGeometry = nullptr;
436 m_triangleGeometry = nullptr;
437
438 if (!m_mesh)
439 return;
440
441 auto *convexMesh = shapeType() == MeshType::CONVEX ? m_mesh->convexMesh() : nullptr;
442 auto *triangleMesh = shapeType() == MeshType::TRIANGLE ? m_mesh->triangleMesh() : nullptr;
443 if (!convexMesh && !triangleMesh)
444 return;
445
446 auto meshScale = sceneScale();
447 physx::PxMeshScale scale(physx::PxVec3(meshScale.x(), meshScale.y(), meshScale.z()),
448 physx::PxQuat(physx::PxIdentity));
449
450 if (convexMesh)
451 m_convexGeometry = new physx::PxConvexMeshGeometry(convexMesh, scale);
452 if (triangleMesh)
453 m_triangleGeometry = new physx::PxTriangleMeshGeometry(triangleMesh, scale);
454
455 m_dirtyPhysx = false;
456}
457
458const QUrl &QMeshShape::source() const
459{
460 return m_meshSource;
461}
462
463void QMeshShape::setSource(const QUrl &newSource)
464{
465 if (m_meshSource == newSource)
466 return;
467 m_meshSource = newSource;
468
469 // If we get a new source and our mesh was from the old source
470 // (meaning it was NOT from a geometry) we deref
471 if (m_geometry == nullptr) {
473 m_mesh = nullptr;
474 }
475
476 // Load new mesh only if we don't have a geometry as source
477 if (m_geometry == nullptr && !newSource.isEmpty())
478 m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this);
479
480 updatePhysXGeometry();
481 m_dirtyPhysx = true;
482
483 emit needsRebuild(this);
484 emit sourceChanged();
485}
486
488{
489 return m_geometry;
490}
491
492void QMeshShape::setGeometry(QQuick3DGeometry *newGeometry)
493{
494 if (m_geometry == newGeometry)
495 return;
496 if (m_geometry)
497 m_geometry->disconnect(this);
498
499 m_geometry = newGeometry;
500
501 if (m_geometry != nullptr) {
502 connect(m_geometry, &QObject::destroyed, this, &QMeshShape::geometryDestroyed);
503 connect(m_geometry, &QQuick3DGeometry::geometryChanged, this,
504 &QMeshShape::geometryContentChanged);
505 }
506
507 // New geometry means we get a new mesh so deref the old one
509 m_mesh = nullptr;
510 if (m_geometry != nullptr)
511 m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_geometry);
512 else if (!m_meshSource.isEmpty())
513 m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_meshSource, this);
514
515 updatePhysXGeometry();
516 m_dirtyPhysx = true;
517 emit needsRebuild(this);
518 emit geometryChanged();
519}
520
521void QMeshShape::geometryDestroyed(QObject *geometry)
522{
523 Q_ASSERT(m_geometry == geometry);
524 // Set geometry to null and the old one will be disconnected and dereferenced
525 setGeometry(nullptr);
526}
527
528void QMeshShape::geometryContentChanged()
529{
530 Q_ASSERT(m_geometry != nullptr);
532 m_mesh = QQuick3DPhysicsMeshManager::getMesh(m_geometry);
533
534 updatePhysXGeometry();
535 m_dirtyPhysx = true;
536 emit needsRebuild(this);
537}
538
void needsRebuild(QObject *)
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
QString absoluteFilePath() const
bool exists() const
Returns true if the file system entry this QFileInfo refers to exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
physx::PxGeometry * getPhysXGeometry() override
virtual MeshType shapeType() const =0
QQuick3DGeometry * geometry
\inmodule QtCore
Definition qobject.h:103
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
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.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
Definition qqmlfile.cpp:742
\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.
QVector3D sceneScale
QVector3D scale
static void releaseMesh(QQuick3DPhysicsMesh *mesh)
static QQuick3DPhysicsMesh * getMesh(const QUrl &source, const QObject *contextObject)
physx::PxTriangleMesh * triangleMesh()
physx::PxConvexMesh * convexMesh()
bool isValid() const
Definition qssgmesh_p.h:159
static Mesh loadMesh(QIODevice *device, quint32 id=0)
Definition qssgmesh.cpp:581
VertexBuffer vertexBuffer() const
Definition qssgmesh_p.h:140
Winding winding() const
Definition qssgmesh_p.h:162
IndexBuffer indexBuffer() const
Definition qssgmesh_p.h:141
QVector< Subset > subsets() const
Definition qssgmesh_p.h:143
DrawMode drawMode() const
Definition qssgmesh_p.h:161
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
\inmodule QtCore
Definition qurl.h:94
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1896
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
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.
static void * context
qsizetype erase_if(QByteArray &ba, Predicate pred)
Definition qbytearray.h:788
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 qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
#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)
Definition qminmax.h:40
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 n
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLuint64EXT * result
[6]
GLenum GLenum GLenum GLenum GLenum scale
GLenum GLenum GLenum input
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
QFile file
[0]
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
QVector< VertexBufferEntry > entries
Definition qssgmesh_p.h:104