11#include <QtQuick3D/QQuick3DGeometry>
12#include <extensions/PxExtensionsAPI.h>
20#include "foundation/PxVec3.h"
22#include "extensions/PxDefaultStreams.h"
23#include "geometry/PxHeightField.h"
24#include "geometry/PxHeightFieldDesc.h"
39 void ref() { ++refCount; }
40 int deref() {
return --refCount; }
49 physx::PxHeightFieldSample *m_samples =
nullptr;
50 physx::PxHeightField *m_heightField =
nullptr;
77 auto *heightField = heightFieldHash.
value(qmlSource);
80 heightFieldHash[qmlSource] = heightField;
88 if (heightField->
deref() == 0) {
89 qCDebug(lcQuick3dPhysics()) <<
"deleting height field" << heightField;
91 [heightField](std::pair<const QString &, QQuick3DPhysicsHeightField *&>
h) {
92 return h.second == heightField;
99 : m_sourcePath(qmlSource)
110 if (!m_samples && !m_sourcePath.
isEmpty()) {
111 QImage heightMap(m_sourcePath);
113 m_rows = heightMap.
height();
114 m_columns = heightMap.
width();
115 int numRows = m_rows;
116 int numCols = m_columns;
118 auto samples =
reinterpret_cast<physx::PxHeightFieldSample *
>(
119 malloc(
sizeof(physx::PxHeightFieldSample) * (numRows * numCols)));
120 for (
int i = 0;
i < numCols;
i++)
121 for (
int j = 0;
j < numRows;
j++) {
135 return m_heightField;
137 physx::PxPhysics *thePhysics = QPhysicsWorld::getPhysics();
138 if (thePhysics ==
nullptr)
142 if (m_heightField !=
nullptr) {
143 m_rows = m_heightField->getNbRows();
144 m_columns = m_heightField->getNbColumns();
145 return m_heightField;
149 if (m_heightField !=
nullptr) {
150 m_rows = m_heightField->getNbRows();
151 m_columns = m_heightField->getNbColumns();
152 return m_heightField;
156 int numRows = m_rows;
157 int numCols = m_columns;
160 physx::PxHeightFieldDesc hfDesc;
161 hfDesc.format = physx::PxHeightFieldFormat::eS16_TM;
162 hfDesc.nbColumns = numRows;
163 hfDesc.nbRows = numCols;
165 hfDesc.samples.stride =
sizeof(physx::PxHeightFieldSample);
167 physx::PxDefaultMemoryOutputStream
buf;
169 const auto cooking = QPhysicsWorld::getCooking();
170 if (numRows && numCols && cooking && cooking->cookHeightField(hfDesc,
buf)) {
174 m_heightField = thePhysics->createHeightField(
input);
175 qCDebug(lcQuick3dPhysics) <<
"created height field" << m_heightField << numCols << numRows
176 <<
"from" << m_sourcePath;
179 qCWarning(lcQuick3dPhysics) <<
"Could not create height field from" << m_sourcePath;
182 return m_heightField;
242 delete m_heightFieldGeometry;
249 if (m_dirtyPhysx || !m_heightFieldGeometry) {
250 updatePhysXGeometry();
252 return m_heightFieldGeometry;
255void QHeightFieldShape::updatePhysXGeometry()
257 delete m_heightFieldGeometry;
258 m_heightFieldGeometry =
nullptr;
263 float rows = m_heightField->
rows();
264 float cols = m_heightField->
columns();
266 if (hf && cols > 1 && rows > 1) {
268 m_heightFieldGeometry =
new physx::PxHeightFieldGeometry(
269 hf, physx::PxMeshGeometryFlags(), scaledExtents.
y() / 0x10000,
270 scaledExtents.
x() / (cols - 1), scaledExtents.
z() / (rows - 1));
271 m_hfOffset = { -scaledExtents.
x() / 2, 0, -scaledExtents.
z() / 2 };
273 qCDebug(lcQuick3dPhysics) <<
"created height field geom" << m_heightFieldGeometry <<
"scale"
274 << scaledExtents << m_heightField->
columns()
275 << m_heightField->
rows();
277 m_dirtyPhysx =
false;
280void QHeightFieldShape::updateExtents()
282 if (!m_heightField || m_extentsSetExplicitly)
284 int numRows = m_heightField->
rows();
285 int numCols = m_heightField->
columns();
286 auto prevExt = m_extents;
287 if (numRows == numCols) {
288 m_extents = { 100, 100, 100 };
289 }
else if (numRows < numCols) {
290 float f = float(numRows) / float(numCols);
291 m_extents = { 100.f, 100.f, 100.f *
f };
293 float f = float(numCols) / float(numRows);
294 m_extents = { 100.f *
f, 100.f, 100.f };
296 if (m_extents != prevExt) {
303 return m_heightMapSource;
306void QHeightFieldShape::setSource(
const QUrl &newSource)
308 if (m_heightMapSource == newSource)
310 m_heightMapSource = newSource;
317 emit sourceChanged();
327 m_extentsSetExplicitly =
true;
328 if (m_extents == newExtents)
330 m_extents = newExtents;
void needsRebuild(QObject *)
float valueF() const noexcept
Returns the value color component of this color.
T value(const Key &key) const noexcept
void setExtents(const QVector3D &newExtents)
physx::PxGeometry * getPhysXGeometry() override
QHeightFieldShape()
\qmltype HeightFieldShape \inqmlmodule QtQuick3D.Physics \inherits CollisionShape
int width() const
Returns the width of the image.
int height() const
Returns the height of the image.
QColor pixelColor(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
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 QFile.
static QQuick3DPhysicsHeightField * getHeightField(const QUrl &source, const QObject *contextObject)
static void releaseHeightField(QQuick3DPhysicsHeightField *heightField)
QQuick3DPhysicsHeightField(const QString &qmlSource)
physx::PxHeightFieldSample * getSamples()
physx::PxHeightField * heightField()
~QQuick3DPhysicsHeightField()
\macro QT_RESTRICTED_CAST_FROM_ASCII
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
The QVector3D class represents a vector or vertex in 3D space.
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
constexpr float z() const noexcept
Returns the z coordinate of this point.
void writeCachedHeightField(const QString &filePath, physx::PxDefaultMemoryOutputStream &buf)
physx::PxHeightField * readCookedHeightField(const QString &filePath, physx::PxPhysics &physics)
physx::PxHeightField * readCachedHeightField(const QString &filePath, physx::PxPhysics &physics)
Combined button and popup list for selecting options.
qsizetype erase_if(QByteArray &ba, Predicate pred)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLenum GLenum GLenum input
QQmlContext * qmlContext(const QObject *obj)
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)