| 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 | |
| 5 | #include "qssgutils_p.h" |
| 6 | |
| 7 | #include <QtCore/QDir> |
| 8 | |
| 9 | #include <cmath> |
| 10 | |
| 11 | QT_BEGIN_NAMESPACE |
| 12 | |
| 13 | float QSSGUtils::vec2::magnitude(const QVector2D &v) |
| 14 | { |
| 15 | return ::sqrtf(x: v.x() * v.x() + v.y() * v.y()); |
| 16 | } |
| 17 | |
| 18 | bool QSSGUtils::vec3::isFinite(const QVector3D &v) |
| 19 | { |
| 20 | return qIsFinite(f: v.x()) && qIsFinite(f: v.y()) && qIsFinite(f: v.z()); |
| 21 | } |
| 22 | |
| 23 | float QSSGUtils::vec3::magnitude(const QVector3D &v) |
| 24 | { |
| 25 | return sqrtf(x: v.x() * v.x() + v.y() * v.y() + v.z() * v.z()); |
| 26 | } |
| 27 | |
| 28 | float QSSGUtils::vec3::magnitudeSquared(const QVector3D &v) |
| 29 | { |
| 30 | return v.x() * v.x() + v.y() * v.y() + v.z() * v.z(); |
| 31 | } |
| 32 | |
| 33 | // This special normalize function normalizes a vector in place |
| 34 | // and returns the magnnitude (needed for compatiblity) |
| 35 | float QSSGUtils::vec3::normalize(QVector3D &v) |
| 36 | { |
| 37 | const float m = QSSGUtils::vec3::magnitude(v); |
| 38 | if (m > 0) |
| 39 | v /= m; |
| 40 | return m; |
| 41 | } |
| 42 | |
| 43 | QVector3D QSSGUtils::mat33::transform(const QMatrix3x3 &m, const QVector3D &v) |
| 44 | { |
| 45 | const QVector3D c0 = QVector3D(m(0, 0), m(1, 0), m(2, 0)); |
| 46 | const QVector3D c1 = QVector3D(m(0, 1), m(1, 1), m(2, 1)); |
| 47 | const QVector3D c2 = QVector3D(m(0, 2), m(1, 2), m(2, 2)); |
| 48 | return c0 * v.x() + c1 * v.y() + c2 * v.z(); |
| 49 | } |
| 50 | |
| 51 | QMatrix3x3 QSSGUtils::mat44::getUpper3x3(const QMatrix4x4 &m) |
| 52 | { |
| 53 | const float values[9] = { m(0, 0), m(0, 1), m(0, 2), m(1, 0), m(1, 1), m(1, 2), m(2, 0), m(2, 1), m(2, 2) }; |
| 54 | return QMatrix3x3(values); |
| 55 | } |
| 56 | |
| 57 | void QSSGUtils::mat44::normalize(QMatrix4x4 &m) |
| 58 | { |
| 59 | QVector4D c0 = m.column(index: 0); |
| 60 | QVector4D c1 = m.column(index: 1); |
| 61 | QVector4D c2 = m.column(index: 2); |
| 62 | QVector4D c3 = m.column(index: 3); |
| 63 | |
| 64 | c0.normalize(); |
| 65 | c1.normalize(); |
| 66 | c2.normalize(); |
| 67 | c3.normalize(); |
| 68 | |
| 69 | m.setColumn(index: 0, value: c0); |
| 70 | m.setColumn(index: 1, value: c1); |
| 71 | m.setColumn(index: 2, value: c2); |
| 72 | m.setColumn(index: 3, value: c3); |
| 73 | } |
| 74 | |
| 75 | QVector3D QSSGUtils::mat44::rotate(const QMatrix4x4 &m, const QVector3D &v) |
| 76 | { |
| 77 | const QVector4D tmp = QSSGUtils::mat44::rotate(m, v: QVector4D(v.x(), v.y(), v.z(), 1.0f)); |
| 78 | return QVector3D(tmp.x(), tmp.y(), tmp.z()); |
| 79 | } |
| 80 | |
| 81 | QVector4D QSSGUtils::mat44::rotate(const QMatrix4x4 &m, const QVector4D &v) |
| 82 | { |
| 83 | return m.column(index: 0) * v.x() + m.column(index: 1) * v.y() + m.column(index: 2) * v.z(); |
| 84 | } |
| 85 | |
| 86 | QVector3D QSSGUtils::mat44::transform(const QMatrix4x4 &m, const QVector3D &v) |
| 87 | { |
| 88 | const QVector4D tmp = QSSGUtils::mat44::transform(m, v: QVector4D(v.x(), v.y(), v.z(), 1.0f)); |
| 89 | return QVector3D(tmp.x(), tmp.y(), tmp.z()); |
| 90 | } |
| 91 | |
| 92 | QVector4D QSSGUtils::mat44::transform(const QMatrix4x4 &m, const QVector4D &v) |
| 93 | { |
| 94 | return m.column(index: 0) * v.x() + m.column(index: 1) * v.y() + m.column(index: 2) * v.z() + m.column(index: 3) * v.w(); |
| 95 | } |
| 96 | |
| 97 | QVector3D QSSGUtils::mat44::getPosition(const QMatrix4x4 &m) |
| 98 | { |
| 99 | return QVector3D(m(0, 3), m(1, 3), m(2, 3)); |
| 100 | } |
| 101 | |
| 102 | QVector3D QSSGUtils::mat44::getScale(const QMatrix4x4 &m) |
| 103 | { |
| 104 | const float scaleX = m.column(index: 0).length(); |
| 105 | const float scaleY = m.column(index: 1).length(); |
| 106 | const float scaleZ = m.column(index: 2).length(); |
| 107 | return QVector3D(scaleX, scaleY, scaleZ); |
| 108 | } |
| 109 | |
| 110 | bool QSSGUtils::quat::isFinite(const QQuaternion &q) |
| 111 | { |
| 112 | return qIsFinite(f: q.x()) && qIsFinite(f: q.y()) && qIsFinite(f: q.z()) && qIsFinite(f: q.scalar()); |
| 113 | } |
| 114 | |
| 115 | float QSSGUtils::quat::magnitude(const QQuaternion &q) |
| 116 | { |
| 117 | return std::sqrt(x: q.x() * q.x() + q.y() * q.y() + q.z() * q.z() + q.scalar() * q.scalar()); |
| 118 | } |
| 119 | |
| 120 | bool QSSGUtils::quat::isSane(const QQuaternion &q) |
| 121 | { |
| 122 | const float unitTolerance = float(1e-2); |
| 123 | return isFinite(q) && qAbs(t: magnitude(q) - 1) < unitTolerance; |
| 124 | } |
| 125 | |
| 126 | bool QSSGUtils::quat::isUnit(const QQuaternion &q) |
| 127 | { |
| 128 | const float unitTolerance = float(1e-4); |
| 129 | return isFinite(q) && qAbs(t: magnitude(q) - 1) < unitTolerance; |
| 130 | } |
| 131 | |
| 132 | QVector3D QSSGUtils::quat::rotated(const QQuaternion &q, const QVector3D &v) |
| 133 | { |
| 134 | const float vx = 2.0f * v.x(); |
| 135 | const float vy = 2.0f * v.y(); |
| 136 | const float vz = 2.0f * v.z(); |
| 137 | const float w2 = q.scalar() * q.scalar() - 0.5f; |
| 138 | const float dot2 = (q.x() * vx + q.y() * vy + q.z() * vz); |
| 139 | return QVector3D((vx * w2 + (q.y() * vz - q.z() * vy) * q.scalar() + q.x() * dot2), |
| 140 | (vy * w2 + (q.z() * vx - q.x() * vz) * q.scalar() + q.y() * dot2), |
| 141 | (vz * w2 + (q.x() * vy - q.y() * vx) * q.scalar() + q.z() * dot2)); |
| 142 | } |
| 143 | |
| 144 | QVector3D QSSGUtils::quat::inverseRotated(const QQuaternion &q, const QVector3D &v) |
| 145 | { |
| 146 | const float vx = 2.0f * v.x(); |
| 147 | const float vy = 2.0f * v.y(); |
| 148 | const float vz = 2.0f * v.z(); |
| 149 | const float w2 = q.scalar() * q.scalar() - 0.5f; |
| 150 | const float dot2 = (q.x() * vx + q.y() * vy + q.z() * vz); |
| 151 | return QVector3D((vx * w2 - (q.y() * vz - q.z() * vy) * q.scalar() + q.x() * dot2), |
| 152 | (vy * w2 - (q.z() * vx - q.x() * vz) * q.scalar() + q.y() * dot2), |
| 153 | (vz * w2 - (q.x() * vy - q.y() * vx) * q.scalar() + q.z() * dot2)); |
| 154 | } |
| 155 | |
| 156 | const char *nonNull(const char *src) |
| 157 | { |
| 158 | return src == nullptr ? "" : src; |
| 159 | } |
| 160 | |
| 161 | QVector4D QSSGUtils::color::sRGBToLinear(const QColor &color) |
| 162 | { |
| 163 | const QVector3D rgb(color.redF(), color.greenF(), color.blueF()); |
| 164 | const float C1 = 0.305306011f; |
| 165 | const QVector3D C2(0.682171111f, 0.682171111f, 0.682171111f); |
| 166 | const QVector3D C3(0.012522878f, 0.012522878f, 0.012522878f); |
| 167 | return QVector4D(rgb * (rgb * (rgb * C1 + C2) + C3), color.alphaF()); |
| 168 | } |
| 169 | |
| 170 | QColor QSSGUtils::color::sRGBToLinearColor(const QColor &color) |
| 171 | { |
| 172 | const QVector4D c = sRGBToLinear(color); |
| 173 | return QColor::fromRgbF(r: c.x(), g: c.y(), b: c.z(), a: c.w()); |
| 174 | } |
| 175 | |
| 176 | bool QSSGUtils::mat44::decompose(const QMatrix4x4 &transform, QVector3D &position, QVector3D &scale, QQuaternion &rotation) |
| 177 | { |
| 178 | QMatrix4x4 m { transform }; |
| 179 | QSSGUtils::mat44::normalize(m); |
| 180 | |
| 181 | rotation = QQuaternion::fromRotationMatrix(rot3x3: QSSGUtils::mat44::getUpper3x3(m)).normalized(); |
| 182 | scale = QSSGUtils::mat44::getScale(m: transform); |
| 183 | position = QSSGUtils::mat44::getPosition(m: transform); |
| 184 | |
| 185 | const auto det = m.determinant(); |
| 186 | |
| 187 | return !qFuzzyIsNull(d: det); |
| 188 | } |
| 189 | |
| 190 | QT_END_NAMESPACE |
| 191 | |