Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgutils_p.h
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6
7#ifndef QSSGUTILS_H
8#define QSSGUTILS_H
9
10//
11// W A R N I N G
12// -------------
13//
14// This file is not part of the Qt API. It exists purely as an
15// implementation detail. This header file may change from version to
16// version without notice, or even be removed.
17//
18// We mean it.
19//
20
21#include <QtQuick3DUtils/private/qtquick3dutilsglobal_p.h>
22#include <QtQuick3DUtils/private/qssgdataref_p.h>
23
24#include <QtGui/QVector2D>
25#include <QtGui/QVector3D>
26#include <QtGui/QQuaternion>
27#include <QtGui/QMatrix3x3>
28#include <QtGui/QMatrix4x4>
29#include <QtGui/QColor>
30
31#include <QtCore/qdebug.h>
32#include <QtCore/QString>
33#include <QtCore/qloggingcategory.h>
34#include <QtCore/QIODevice>
35#include <QtCore/qmath.h>
36
37class tst_RotationDataClass;
38
39QT_BEGIN_NAMESPACE
40
41enum class HandleType
42{
43 Layer,
44 Node,
45 Model,
46 Item2D
47};
48
49using QSSGRenderNodeVersionType = quint16;
50
51template <HandleType>
53{
54public:
61
63 explicit QSSGRenderStorageHandle(ContextType ctx, VersionType version, IndexType index)
65 {
66 }
67
68 // NOTE: Version should always be > 0 when used (0 = default-constructed / invalid).
69 bool hasId() const { return m_id != 0; }
70
71 ContextType context() const { return m_ctx; }
72 VersionType version() const { return m_version; }
73 IndexType index() const { return m_index; }
74
75 quint64 id() const { return m_id; }
76
77private:
78 union {
79 struct {
80 quint64 m_ctx : ContextBits;
81 quint64 m_version : VersionBits;
82 quint64 m_index : IndexBits;
83 };
85 };
86};
87
92
94{
95public:
96 QSSGRenderFlag() = default;
97 explicit QSSGRenderFlag(quint32 v)
98 : m_value(v)
99 {
100 }
101
102 [[nodiscard]] quint32 value() const { return m_value; }
103
104 void setValue(quint32 v)
105 {
106 m_value = v;
107 }
108
109 void clearFlags(quint32 v = 0xFFFFFFFF)
110 {
111 m_value &= ~v;
112 }
113
114 void setFlag(quint32 v, bool on = true)
115 {
116 if (on)
117 m_value |= v;
118 else
119 m_value &= ~v;
120 }
121
122 [[nodiscard]] bool isSet(quint32 v) const { return (m_value & v) != 0; }
123
124 friend bool operator==(const QSSGRenderFlag &a, const QSSGRenderFlag &b);
125 friend bool operator!=(const QSSGRenderFlag &a, const QSSGRenderFlag &b);
126
127 operator quint32() const noexcept { return m_value; }
128
129private:
130 quint32 m_value = 0;
131};
132
133inline bool operator==(const QSSGRenderFlag &a, const QSSGRenderFlag &b)
134{
135 return a.m_value == b.m_value;
136}
137
138inline bool operator!=(const QSSGRenderFlag &a, const QSSGRenderFlag &b)
139{
140 return !(a == b);
141}
142
144
145
146namespace QSSGUtils {
147
148namespace aux {
149Q_DECL_CONSTEXPR inline float translateConstantAttenuation(float attenuation) { return attenuation; }
150template<int MINATTENUATION = 0, int MAXATTENUATION = 1000>
151Q_DECL_CONSTEXPR inline float translateLinearAttenuation(float attenuation) { return qBound(float(MINATTENUATION), attenuation, float(MAXATTENUATION)) * .01f; }
152template<int MINATTENUATION = 0, int MAXATTENUATION = 1000>
153Q_DECL_CONSTEXPR inline float translateQuadraticAttenuation(float attenuation) { return qBound(float(MINATTENUATION), attenuation, float(MAXATTENUATION)) * .0001f; }
154}
155
156namespace vec2 {
157float Q_QUICK3DUTILS_EXPORT magnitude(const QVector2D &v);
158}
159
160namespace vec3 {
161inline QVector3D minimum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW { return { qMin(v1.x(), v2.x()), qMin(v1.y(), v2.y()), qMin(v1.z(), v2.z()) }; }
162inline QVector3D maximum(const QVector3D &v1, const QVector3D &v2) Q_DECL_NOTHROW { return { qMax(v1.x(), v2.x()), qMax(v1.y(), v2.y()), qMax(v1.z(), v2.z()) }; }
164float Q_QUICK3DUTILS_EXPORT magnitude(const QVector3D &v);
165float Q_QUICK3DUTILS_EXPORT magnitudeSquared(const QVector3D &v);
166float Q_QUICK3DUTILS_EXPORT normalize(QVector3D &v);
167}
168
169namespace mat33 {
170QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix3x3 &m, const QVector3D &v);
171}
172
173namespace mat44 {
174QMatrix3x3 Q_QUICK3DUTILS_EXPORT getUpper3x3(const QMatrix4x4 &m);
175void Q_QUICK3DUTILS_EXPORT normalize(QMatrix4x4 &m);
176QVector3D Q_QUICK3DUTILS_EXPORT rotate(const QMatrix4x4 &m, const QVector3D &v);
177QVector4D Q_QUICK3DUTILS_EXPORT rotate(const QMatrix4x4 &m, const QVector4D &v);
178QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix4x4 &m, const QVector3D &v);
179QVector4D Q_QUICK3DUTILS_EXPORT transform(const QMatrix4x4 &m, const QVector4D &v);
180QVector3D Q_QUICK3DUTILS_EXPORT getPosition(const QMatrix4x4 &m);
181QVector3D Q_QUICK3DUTILS_EXPORT getScale(const QMatrix4x4 &m);
182
183bool Q_QUICK3DUTILS_EXPORT decompose(const QMatrix4x4 &m, QVector3D &position, QVector3D &scale, QQuaternion &rotation);
184
185inline void flip(QMatrix4x4 &matrix)
186{
187 // Flip between left-handed and right-handed orientation
188 float *writePtr(matrix.data());
189 // rotation conversion
190 writePtr[0 * 4 + 2] *= -1;
191 writePtr[1 * 4 + 2] *= -1;
192 writePtr[2 * 4 + 0] *= -1;
193 writePtr[2 * 4 + 1] *= -1;
194 // translation conversion
195 writePtr[3 * 4 + 2] *= -1;
196}
197
198}
199
200namespace quat {
201bool Q_QUICK3DUTILS_EXPORT isFinite(const QQuaternion &q);
202
203float Q_QUICK3DUTILS_EXPORT magnitude(const QQuaternion &q);
204
205bool Q_QUICK3DUTILS_EXPORT isSane(const QQuaternion &q);
206
207bool Q_QUICK3DUTILS_EXPORT isUnit(const QQuaternion &q);
208
209QVector3D Q_QUICK3DUTILS_EXPORT rotated(const QQuaternion &q, const QVector3D &v);
210
211QVector3D Q_QUICK3DUTILS_EXPORT inverseRotated(const QQuaternion &q, const QVector3D &v);
212}
213
214namespace color {
215QColor Q_QUICK3DUTILS_EXPORT linearTosRGB(const QVector4D &linearColorFactor);
216QVector4D Q_QUICK3DUTILS_EXPORT sRGBToLinear(const QColor &color);
217QColor Q_QUICK3DUTILS_EXPORT sRGBToLinearColor(const QColor &color);
218}
219
220template<typename TDataType>
221QSSGDataRef<TDataType> PtrAtOffset(quint8 *baseData, quint32 offset, quint32 byteSize)
222{
223 return QSSGDataRef<TDataType>(byteSize ? reinterpret_cast<TDataType *>(baseData + offset) : nullptr,
224 byteSize / sizeof(TDataType));
225}
226
227Q_QUICK3DUTILS_EXPORT const char *nonNull(const char *src);
228
229inline QVector3D degToRad(const QVector3D &v) {
230 return QVector3D(qDegreesToRadians(v.x()), qDegreesToRadians(v.y()), qDegreesToRadians(v.z()));
231}
232
233inline QVector3D radToDeg(const QVector3D &v) {
234 return QVector3D(qRadiansToDegrees(v.x()), qRadiansToDegrees(v.y()), qRadiansToDegrees(v.z()));
235}
236
237namespace rect {
238// Return coordinates in pixels but relative to this rect.
239inline QVector2D toRectRelative(const QRectF &r, const QVector2D &absoluteCoordinates)
240{
241 return QVector2D(absoluteCoordinates.x() - float(r.x()), absoluteCoordinates.y() - float(r.y()));
242}
243
244inline QVector2D halfDims(const QRectF &r)
245{
246 return QVector2D(float(r.width() / 2.0), float(r.height() / 2.0));
247}
248
249// Take coordinates in global space and move local space where 0,0 is the center
250// of the rect but return value in pixels, not in normalized -1,1 range
251inline QVector2D toNormalizedRectRelative(const QRectF &r, QVector2D absoluteCoordinates)
252{
253 // normalize them
254 const QVector2D relativeCoords(toRectRelative(r, absoluteCoordinates));
255 const QVector2D halfD(halfDims(r));
256 const QVector2D normalized((relativeCoords.x() / halfD.x()) - 1.0f, (relativeCoords.y() / halfD.y()) - 1.0f);
257 return QVector2D(normalized.x() * halfD.x(), normalized.y() * halfD.y());
258}
259
260inline QVector2D relativeToNormalizedCoordinates(const QRectF &r, QVector2D rectRelativeCoords)
261{
262 return { (rectRelativeCoords.x() / halfDims(r).x()) - 1.0f, (rectRelativeCoords.y() / halfDims(r).y()) - 1.0f };
263}
264
265// Normalized coordinates are in the range of -1,1 where -1 is the left, bottom edges
266// and 1 is the top,right edges.
267inline QVector2D absoluteToNormalizedCoordinates(const QRectF &r, const QVector2D &absoluteCoordinates)
268{
269 return relativeToNormalizedCoordinates(r, toRectRelative(r, absoluteCoordinates));
270}
271
272inline QVector2D toAbsoluteCoords(const QRectF &r, const QVector2D &inRelativeCoords)
273{
274 return QVector2D(inRelativeCoords.x() + float(r.x()), inRelativeCoords.y() + float(r.y()));
275}
276}
277
278} // namespace QSSGUtils
279
281{
282public:
283 RotationData() = default;
284 explicit RotationData(const QVector3D &r)
285 : m_quatRot()
286 , m_eulerRot(r)
287 , m_dirty(Dirty::Quaternion)
288 {}
289 explicit RotationData(const QQuaternion &r)
291 , m_eulerRot()
292 , m_dirty(Dirty::Euler)
293 {}
294
295 RotationData &operator=(const QVector3D &r) noexcept
296 {
297 m_eulerRot = r;
298 m_dirty = Dirty::Quaternion;
299 return *this;
300 }
301 RotationData &operator=(const QQuaternion &r) noexcept
302 {
303 m_quatRot = r.normalized();
304 m_dirty = Dirty::Euler;
305 return *this;
306 }
307
308 friend bool operator ==(const RotationData &a, const RotationData &b) {
309 if (a.m_dirty == Dirty::None && b.m_dirty == Dirty::None)
310 return fuzzyQuaternionCompare(a.m_quatRot, b.m_quatRot);
311
312 return fuzzyQuaternionCompare(a.toQuaternion(), b.toQuaternion());
313 }
314
315 friend bool operator !=(const RotationData &a, const RotationData &b) { return !(a == b); }
316
317 friend bool operator ==(const RotationData &a, const QVector3D &eulerRotation)
318 {
319 if (a.m_dirty == Dirty::None)
320 return qFuzzyCompare(a.m_eulerRot, eulerRotation);
321
322 return qFuzzyCompare(a.toEulerAngles(), eulerRotation);
323 }
324
325 friend bool operator !=(const RotationData &a, const QVector3D &eulerRotation) { return !(a == eulerRotation); }
326
327 friend bool operator ==(const QVector3D &eulerRotation, const RotationData &a) { return a == eulerRotation; }
328 friend bool operator !=(const QVector3D &eulerRotation, const RotationData &a) { return !(a == eulerRotation); }
329
330 friend bool operator ==(const RotationData &a, const QQuaternion &rotation)
331 {
332 const QQuaternion normalizedRotation = rotation.normalized();
333 if (a.m_dirty == Dirty::None)
334 return fuzzyQuaternionCompare(a.m_quatRot, normalizedRotation);
335
336 return fuzzyQuaternionCompare(a.toQuaternion(), normalizedRotation);
337 }
338 friend bool operator !=(const RotationData &a, const QQuaternion &rotation) { return !(a == rotation); }
339
340 friend bool operator ==(const QQuaternion &rotation, const RotationData &a) { return a == rotation; }
341 friend bool operator !=(const QQuaternion &rotation, const RotationData &a) { return !(a == rotation); }
342
343 [[nodiscard]] inline QVector3D toEulerAngles() const
344 {
345 if (m_dirty == Dirty::Euler) {
346 m_eulerRot = m_quatRot.toEulerAngles();
347 m_dirty = Dirty::None;
348 }
349
350 return m_eulerRot;
351 }
352
353 [[nodiscard]] inline QQuaternion toQuaternion() const
354 {
355 if (m_dirty == Dirty::Quaternion) {
356 m_quatRot = QQuaternion::fromEulerAngles(m_eulerRot).normalized();
357 m_dirty = Dirty::None;
358 }
359
360 return m_quatRot;
361 }
362
363 [[nodiscard]] inline QMatrix3x3 toRotationMatrix() const { return toQuaternion().toRotationMatrix(); }
364
365private:
366 friend class ::tst_RotationDataClass;
367
368 static constexpr double dotProduct(const QQuaternion &q1, const QQuaternion &q2) noexcept
369 {
370 return double(q1.scalar()) * double(q2.scalar())
371 + double(q1.x()) * double(q2.x())
372 + double(q1.y()) * double(q2.y())
373 + double(q1.z()) * double(q2.z());
374 }
375
376 [[nodiscard]] static constexpr bool fuzzyQuaternionCompare(const QQuaternion &a, const QQuaternion &b)
377 {
378 // Do a component for component check, this ensures that we skip the expensive call when we
379 // anyway have a perfect match or an exact opposite match (which is also the same rotation).
380 if (a == b || a == -b)
381 return true;
382 return qFuzzyCompare(qAbs(dotProduct(a, b)), 1.0);
383 }
384
385 enum class Dirty
386 {
387 None,
388 Quaternion = 0x1,
389 Euler = 0x2
390 };
391
392 mutable QQuaternion m_quatRot; // Should always be normalized
393 mutable QVector3D m_eulerRot;
394 mutable Dirty m_dirty { Dirty::None };
395};
396
398template<typename T>
399inline void ensureDebugObjectName(T *node, QObject *src)
400{
401 if (!node->debugObjectName.isEmpty())
402 return;
403 node->debugObjectName = src->objectName();
404 if (node->debugObjectName.isEmpty())
405 node->debugObjectName = QString::fromLatin1(src->metaObject()->className());
406 if (node->debugObjectName.isEmpty())
407 node->debugObjectName = QString::asprintf("%p", src);
408}
409}
410
411QT_END_NAMESPACE
412
413#endif // QSSGUTILS_H
Class representing 3D range or axis aligned bounding box.
void setValue(quint32 v)
void clearFlags(quint32 v=0xFFFFFFFF)
friend bool operator!=(const QSSGRenderFlag &a, const QSSGRenderFlag &b)
QSSGRenderFlag(quint32 v)
Definition qssgutils_p.h:97
friend bool operator==(const QSSGRenderFlag &a, const QSSGRenderFlag &b)
void setFlag(quint32 v, bool on=true)
QSSGRenderFlag()=default
bool isSet(quint32 v) const
quint32 value() const
static constexpr size_t VersionBits
Definition qssgutils_p.h:59
QSSGRenderStorageHandle()=default
IndexType index() const
Definition qssgutils_p.h:73
VersionType version() const
Definition qssgutils_p.h:72
QSSGRenderStorageHandle(ContextType ctx, VersionType version, IndexType index)
Definition qssgutils_p.h:63
static constexpr size_t ContextBits
Definition qssgutils_p.h:58
static constexpr size_t IndexBits
Definition qssgutils_p.h:60
quint64 id() const
Definition qssgutils_p.h:75
ContextType context() const
Definition qssgutils_p.h:71
QQuaternion toQuaternion() const
RotationData(const QVector3D &r)
friend bool operator!=(const RotationData &a, const RotationData &b)
friend bool operator!=(const QVector3D &eulerRotation, const RotationData &a)
friend bool operator==(const QVector3D &eulerRotation, const RotationData &a)
friend bool operator!=(const RotationData &a, const QVector3D &eulerRotation)
QVector3D toEulerAngles() const
friend bool operator==(const RotationData &a, const QVector3D &eulerRotation)
QMatrix3x3 toRotationMatrix() const
RotationData()=default
friend bool operator==(const RotationData &a, const RotationData &b)
RotationData & operator=(const QVector3D &r) noexcept
void ensureDebugObjectName(T *node, QObject *src)
Q_DECL_CONSTEXPR float translateLinearAttenuation(float attenuation)
Q_DECL_CONSTEXPR float translateConstantAttenuation(float attenuation)
Q_DECL_CONSTEXPR float translateQuadraticAttenuation(float attenuation)
void flip(QMatrix4x4 &matrix)
QVector2D toRectRelative(const QRectF &r, const QVector2D &absoluteCoordinates)
QVector2D halfDims(const QRectF &r)
QVector2D toAbsoluteCoords(const QRectF &r, const QVector2D &inRelativeCoords)
QVector2D absoluteToNormalizedCoordinates(const QRectF &r, const QVector2D &absoluteCoordinates)
QVector2D relativeToNormalizedCoordinates(const QRectF &r, QVector2D rectRelativeCoords)
QVector2D toNormalizedRectRelative(const QRectF &r, QVector2D absoluteCoordinates)
QVector3D radToDeg(const QVector3D &v)
QSSGDataRef< TDataType > PtrAtOffset(quint8 *baseData, quint32 offset, quint32 byteSize)
Q_QUICK3DUTILS_EXPORT const char * nonNull(const char *src)
QVector3D degToRad(const QVector3D &v)
Combined button and popup list for selecting options.
QSSGRenderFlag QSSGRenderNodeTag
QSSGRenderStorageHandle< HandleType::Node > QSSGRenderNodeHandle
Definition qssgutils_p.h:89
QSSGRenderStorageHandle< HandleType::Item2D > QSSGRenderItem2DHandle
Definition qssgutils_p.h:91
QSSGRenderStorageHandle< HandleType::Model > QSSGRenderModelHandle
Definition qssgutils_p.h:90
QSSGRenderStorageHandle< HandleType::Layer > QSSGRenderLayerHandle
Definition qssgutils_p.h:88