General: Mark functions as nodiscard where applicable

Given this aims to be a general purpose math library for use in various
other libraries applications for axiodl, we can annotate functions that
return by value or reference with [[nodiscard]] where it's very obvious
that not making use of the return value is a bug.

This allows the compiler to diagnose and emit warnings for these API
misuses at compile-time, preventing silent bugs from occurring.

Any cases where not using the return value is desirable may still be
casted to void in order to silence warnings.
This commit is contained in:
Lioncash 2020-02-29 04:33:29 -05:00
parent 97cec53046
commit 81f9b4a4ee
21 changed files with 474 additions and 414 deletions

View File

@ -47,7 +47,7 @@ public:
max.readBig(in);
}
static CAABox ReadBoundingBoxBig(athena::io::IStreamReader& in) {
[[nodiscard]] static CAABox ReadBoundingBoxBig(athena::io::IStreamReader& in) {
CAABox ret;
ret.readBoundingBoxBig(in);
return ret;
@ -55,28 +55,28 @@ public:
#endif
bool intersects(const CAABox& other) const {
bool x1 = (max[0] >= other.min[0]);
bool x2 = (min[0] <= other.max[0]);
bool y1 = (max[1] >= other.min[1]);
bool y2 = (min[1] <= other.max[1]);
bool z1 = (max[2] >= other.min[2]);
bool z2 = (min[2] <= other.max[2]);
[[nodiscard]] bool intersects(const CAABox& other) const {
const bool x1 = max[0] >= other.min[0];
const bool x2 = min[0] <= other.max[0];
const bool y1 = max[1] >= other.min[1];
const bool y2 = min[1] <= other.max[1];
const bool z1 = max[2] >= other.min[2];
const bool z2 = min[2] <= other.max[2];
return x1 && x2 && y1 && y2 && z1 && z2;
}
bool intersects(const CSphere& other) const;
float intersectionRadius(const CSphere& other) const;
CAABox booleanIntersection(const CAABox& other) const;
[[nodiscard]] bool intersects(const CSphere& other) const;
[[nodiscard]] float intersectionRadius(const CSphere& other) const;
[[nodiscard]] CAABox booleanIntersection(const CAABox& other) const;
bool inside(const CAABox& other) const {
bool x = min[0] >= other.min[0] && max[0] <= other.max[0];
bool y = min[1] >= other.min[1] && max[1] <= other.max[1];
bool z = min[2] >= other.min[2] && max[2] <= other.max[2];
[[nodiscard]] bool inside(const CAABox& other) const {
const bool x = min[0] >= other.min[0] && max[0] <= other.max[0];
const bool y = min[1] >= other.min[1] && max[1] <= other.max[1];
const bool z = min[2] >= other.min[2] && max[2] <= other.max[2];
return x && y && z;
}
bool insidePlane(const CPlane& plane) const {
[[nodiscard]] bool insidePlane(const CPlane& plane) const {
CVector3f vmax;
/* X axis */
if (plane.x() >= 0.f)
@ -96,16 +96,16 @@ public:
return plane.normal().dot(vmax) + plane.d() >= 0.f;
}
CVector3f center() const { return (min + max) * 0.5f; }
[[nodiscard]] CVector3f center() const { return (min + max) * 0.5f; }
CVector3f extents() const { return (max - min) * 0.5f; }
[[nodiscard]] CVector3f extents() const { return (max - min) * 0.5f; }
float volume() const {
auto delta = max - min;
[[nodiscard]] float volume() const {
const auto delta = max - min;
return delta.x() * delta.y() * delta.z();
}
CLineSeg getEdge(EBoxEdgeId id) const {
[[nodiscard]] CLineSeg getEdge(EBoxEdgeId id) const {
switch (id) {
case EBoxEdgeId::Z0:
default:
@ -139,9 +139,9 @@ public:
zeus::CPlane x0_plane;
zeus::CVector3f x10_verts[3];
};
Tri getTri(EBoxFaceId face, int windOffset) const;
[[nodiscard]] Tri getTri(EBoxFaceId face, int windOffset) const;
CAABox getTransformedAABox(const CTransform& xfrm) const {
[[nodiscard]] CAABox getTransformedAABox(const CTransform& xfrm) const {
CAABox box;
CVector3f point = xfrm * getPoint(0);
box.accumulateBounds(point);
@ -182,22 +182,22 @@ public:
accumulateBounds(other.max);
}
bool pointInside(const CVector3f& other) const {
[[nodiscard]] bool pointInside(const CVector3f& other) const {
return (min.x() <= other.x() && other.x() <= max.x() && min.y() <= other.y() && other.y() <= max.y() &&
min.z() <= other.z() && other.z() <= max.z());
}
CVector3f closestPointAlongVector(const CVector3f& other) const {
[[nodiscard]] CVector3f closestPointAlongVector(const CVector3f& other) const {
return {(other.x() >= 0.f ? min.x() : max.x()), (other.y() >= 0.f ? min.y() : max.y()),
(other.z() >= 0.f ? min.z() : max.z())};
}
CVector3f furthestPointAlongVector(const CVector3f& other) const {
[[nodiscard]] CVector3f furthestPointAlongVector(const CVector3f& other) const {
return {(other.x() >= 0.f ? max.x() : min.x()), (other.y() >= 0.f ? max.y() : min.y()),
(other.z() >= 0.f ? max.z() : min.z())};
}
float distanceBetween(const CAABox& other) {
[[nodiscard]] float distanceBetween(const CAABox& other) const {
int intersects = 0;
if (max.x() >= other.min.x() && min.x() <= other.max.x())
intersects |= 0x1;
@ -254,12 +254,12 @@ public:
}
}
CVector3f getPoint(const int point) const {
[[nodiscard]] CVector3f getPoint(const int point) const {
const CVector3f* vecs = &min;
return CVector3f(vecs[(point & 1) != 0].x(), vecs[(point & 2) != 0].y(), vecs[(point & 4) != 0].z());
}
CVector3f clampToBox(const CVector3f& vec) const {
[[nodiscard]] CVector3f clampToBox(const CVector3f& vec) const {
CVector3f ret = vec;
ret.x() = clamp(min.x(), float(ret.x()), max.x());
ret.y() = clamp(min.y(), float(ret.y()), max.y());
@ -267,7 +267,7 @@ public:
return ret;
}
bool projectedPointTest(const CMatrix4f& mvp, const CVector2f& point) const;
[[nodiscard]] bool projectedPointTest(const CMatrix4f& mvp, const CVector2f& point) const;
void splitX(CAABox& negX, CAABox& posX) const {
float midX = (max.x() - min.x()) * .5f + min.x();
@ -299,9 +299,9 @@ public:
negZ.min = min;
}
bool invalid() { return (max.x() < min.x() || max.y() < min.y() || max.z() < min.z()); }
[[nodiscard]] bool invalid() const { return max.x() < min.x() || max.y() < min.y() || max.z() < min.z(); }
float operator[](size_t idx) const {
[[nodiscard]] float operator[](size_t idx) const {
assert(idx < 6);
if (idx < 3)
return min[idx];
@ -312,11 +312,11 @@ public:
constexpr CAABox skInvertedBox;
constexpr CAABox skNullBox(CVector3f{}, CVector3f{});
inline bool operator==(const CAABox& left, const CAABox& right) {
[[nodiscard]] inline bool operator==(const CAABox& left, const CAABox& right) {
return (left.min == right.min && left.max == right.max);
}
inline bool operator!=(const CAABox& left, const CAABox& right) {
[[nodiscard]] inline bool operator!=(const CAABox& left, const CAABox& right) {
return (left.min != right.min || left.max != right.max);
}
} // namespace zeus

View File

@ -9,7 +9,8 @@ struct CAxisAngle : CVector3f {
constexpr CAxisAngle(float x, float y, float z) : CVector3f(x, y, z) {}
CAxisAngle(const CUnitVector3f& axis, float angle) : CVector3f(angle * axis) {}
constexpr CAxisAngle(const CVector3f& axisAngle) : CVector3f(axisAngle) {}
float angle() const { return magnitude(); }
const CVector3f& getVector() const { return *this; }
[[nodiscard]] float angle() const { return magnitude(); }
[[nodiscard]] const CVector3f& getVector() const { return *this; }
};
} // namespace zeus

View File

@ -76,7 +76,7 @@ public:
#if ZE_ATHENA_TYPES
static CColor ReadRGBABig(athena::io::IStreamReader& reader) {
[[nodiscard]] static CColor ReadRGBABig(athena::io::IStreamReader& reader) {
CColor ret;
ret.readRGBABig(reader);
return ret;
@ -126,27 +126,27 @@ public:
#endif
bool operator==(const CColor& rhs) const {
[[nodiscard]] bool operator==(const CColor& rhs) const {
return (r() == rhs.r() && g() == rhs.g() && b() == rhs.b() && a() == rhs.a());
}
bool operator!=(const CColor& rhs) const { return !(*this == rhs); }
[[nodiscard]] bool operator!=(const CColor& rhs) const { return !(*this == rhs); }
CColor operator+(const CColor& rhs) const { return CColor(mSimd + rhs.mSimd).Clamp(); }
[[nodiscard]] CColor operator+(const CColor& rhs) const { return CColor(mSimd + rhs.mSimd).Clamp(); }
CColor operator-(const CColor& rhs) const { return CColor(mSimd - rhs.mSimd).Clamp(); }
[[nodiscard]] CColor operator-(const CColor& rhs) const { return CColor(mSimd - rhs.mSimd).Clamp(); }
CColor operator*(const CColor& rhs) const { return CColor(mSimd * rhs.mSimd).Clamp(); }
[[nodiscard]] CColor operator*(const CColor& rhs) const { return CColor(mSimd * rhs.mSimd).Clamp(); }
CColor operator/(const CColor& rhs) const { return CColor(mSimd / rhs.mSimd).Clamp(); }
[[nodiscard]] CColor operator/(const CColor& rhs) const { return CColor(mSimd / rhs.mSimd).Clamp(); }
CColor operator+(float val) const { return CColor(mSimd + simd<float>(val)).Clamp(); }
[[nodiscard]] CColor operator+(float val) const { return CColor(mSimd + simd<float>(val)).Clamp(); }
CColor operator-(float val) const { return CColor(mSimd - simd<float>(val)).Clamp(); }
[[nodiscard]] CColor operator-(float val) const { return CColor(mSimd - simd<float>(val)).Clamp(); }
CColor operator*(float val) const { return CColor(mSimd * simd<float>(val)).Clamp(); }
[[nodiscard]] CColor operator*(float val) const { return CColor(mSimd * simd<float>(val)).Clamp(); }
CColor operator/(float val) const { return CColor(mSimd / simd<float>(val)).Clamp(); }
[[nodiscard]] CColor operator/(float val) const { return CColor(mSimd / simd<float>(val)).Clamp(); }
const CColor& operator+=(const CColor& rhs) {
mSimd += rhs.mSimd;
@ -202,28 +202,28 @@ public:
*this *= mag;
}
CColor normalized() const {
[[nodiscard]] CColor normalized() const {
float mag = magnitude();
mag = 1.f / mag;
return *this * mag;
}
float magSquared() const { return mSimd.dot4(mSimd); }
[[nodiscard]] float magSquared() const { return mSimd.dot4(mSimd); }
float magnitude() const { return std::sqrt(magSquared()); }
[[nodiscard]] float magnitude() const { return std::sqrt(magSquared()); }
static CColor lerp(const CColor& a, const CColor& b, float t) {
[[nodiscard]] static CColor lerp(const CColor& a, const CColor& b, float t) {
return zeus::simd<float>(1.f - t) * a.mSimd + b.mSimd * zeus::simd<float>(t);
}
static CColor nlerp(const CColor& a, const CColor& b, float t) { return lerp(a, b, t).normalized(); }
[[nodiscard]] static CColor nlerp(const CColor& a, const CColor& b, float t) { return lerp(a, b, t).normalized(); }
simd<float>::reference operator[](const size_t& idx) {
[[nodiscard]] simd<float>::reference operator[](const size_t& idx) {
assert(idx < 4);
return mSimd[idx];
}
float operator[](const size_t& idx) const {
[[nodiscard]] float operator[](const size_t& idx) const {
assert(idx < 4);
return mSimd[idx];
}
@ -233,7 +233,7 @@ public:
mSimd[3] = a;
}
float rgbDot(const CColor& rhs) const { return mSimd.dot3(rhs.mSimd); }
[[nodiscard]] float rgbDot(const CColor& rhs) const { return mSimd.dot3(rhs.mSimd); }
void fromRGBA8(const Comp8 ri, const Comp8 gi, const Comp8 bi, const Comp8 ai) {
mSimd = simd<float>(ri * OneOver255, gi * OneOver255, bi * OneOver255, ai * OneOver255);
@ -280,7 +280,7 @@ public:
void toHSL(float& h, float& s, float& l) const;
CColor toGrayscale() const { return {std::sqrt((r() * r() + g() * g() + b() * b()) / 3), a()}; }
[[nodiscard]] CColor toGrayscale() const { return {std::sqrt((r() * r() + g() * g() + b() * b()) / 3), a()}; }
/**
* @brief Clamps to GPU-safe RGBA values [0,1]
@ -293,15 +293,15 @@ public:
return *this;
}
float r() const { return mSimd[0]; }
float g() const { return mSimd[1]; }
float b() const { return mSimd[2]; }
float a() const { return mSimd[3]; }
[[nodiscard]] float r() const { return mSimd[0]; }
[[nodiscard]] float g() const { return mSimd[1]; }
[[nodiscard]] float b() const { return mSimd[2]; }
[[nodiscard]] float a() const { return mSimd[3]; }
simd<float>::reference r() { return mSimd[0]; }
simd<float>::reference g() { return mSimd[1]; }
simd<float>::reference b() { return mSimd[2]; }
simd<float>::reference a() { return mSimd[3]; }
[[nodiscard]] simd<float>::reference r() { return mSimd[0]; }
[[nodiscard]] simd<float>::reference g() { return mSimd[1]; }
[[nodiscard]] simd<float>::reference b() { return mSimd[2]; }
[[nodiscard]] simd<float>::reference a() { return mSimd[3]; }
};
constexpr CVector4f::CVector4f(const zeus::CColor& other) : mSimd(other.mSimd) {}
@ -323,13 +323,21 @@ constexpr CColor skYellow(1.f, 1.f, 0.f, 1.f);
constexpr CColor skWhite(1.f, 1.f, 1.f, 1.f);
constexpr CColor skClear(0.f, 0.f, 0.f, 0.f);
inline CColor operator+(float lhs, const CColor& rhs) { return CColor(simd<float>(lhs) + rhs.mSimd).Clamp(); }
[[nodiscard]] inline CColor operator+(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) + rhs.mSimd).Clamp();
}
inline CColor operator-(float lhs, const CColor& rhs) { return CColor(simd<float>(lhs) - rhs.mSimd).Clamp(); }
[[nodiscard]] inline CColor operator-(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) - rhs.mSimd).Clamp();
}
inline CColor operator*(float lhs, const CColor& rhs) { return CColor(simd<float>(lhs) * rhs.mSimd).Clamp(); }
[[nodiscard]] inline CColor operator*(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) * rhs.mSimd).Clamp();
}
inline CColor operator/(float lhs, const CColor& rhs) { return CColor(simd<float>(lhs) / rhs.mSimd).Clamp(); }
[[nodiscard]] inline CColor operator/(float lhs, const CColor& rhs) {
return CColor(simd<float>(lhs) / rhs.mSimd).Clamp();
}
} // namespace zeus
namespace std {

View File

@ -16,8 +16,8 @@ class CFrustum {
public:
void updatePlanes(const CMatrix4f& viewMtx, const CMatrix4f& projection);
void updatePlanes(const CTransform& viewPointMtx, const CProjection& projection);
bool aabbFrustumTest(const CAABox& aabb) const;
bool sphereFrustumTest(const CSphere& sphere) const;
bool pointFrustumTest(const CVector3f& point) const;
[[nodiscard]] bool aabbFrustumTest(const CAABox& aabb) const;
[[nodiscard]] bool sphereFrustumTest(const CSphere& sphere) const;
[[nodiscard]] bool pointFrustumTest(const CVector3f& point) const;
};
} // namespace zeus

View File

@ -17,7 +17,7 @@ struct CMRay {
dir = invLen * delta;
}
CMRay getInvUnscaledTransformRay(const CTransform& xfrm) const {
[[nodiscard]] CMRay getInvUnscaledTransformRay(const CTransform& xfrm) const {
const CTransform inv = xfrm.inverse();
return CMRay(inv * start, inv * end, length, invLength);
}

View File

@ -61,7 +61,7 @@ public:
m[2][2] = input.readFloatBig();
}
static CMatrix3f ReadBig(athena::io::IStreamReader& input) {
[[nodiscard]] static CMatrix3f ReadBig(athena::io::IStreamReader& input) {
CMatrix3f ret;
ret.readBig(input);
return ret;
@ -73,22 +73,22 @@ public:
CMatrix3f& operator=(const CMatrix3f& other) = default;
CVector3f operator*(const CVector3f& other) const {
[[nodiscard]] CVector3f operator*(const CVector3f& other) const {
return m[0].mSimd * other.mSimd.shuffle<0, 0, 0, 0>() + m[1].mSimd * other.mSimd.shuffle<1, 1, 1, 1>() +
m[2].mSimd * other.mSimd.shuffle<2, 2, 2, 2>();
}
CVector3f& operator[](size_t i) {
[[nodiscard]] CVector3f& operator[](size_t i) {
assert(i < m.size());
return m[i];
}
const CVector3f& operator[](size_t i) const {
[[nodiscard]] const CVector3f& operator[](size_t i) const {
assert(i < m.size());
return m[i];
}
CMatrix3f orthonormalized() const {
[[nodiscard]] CMatrix3f orthonormalized() const {
CMatrix3f ret;
ret[0] = m[0].normalized();
ret[2] = ret[0].cross(m[1]);
@ -97,17 +97,19 @@ public:
return ret;
}
bool operator==(const CMatrix3f& other) const {
[[nodiscard]] bool operator==(const CMatrix3f& other) const {
return m[0] == other.m[0] && m[1] == other.m[1] && m[2] == other.m[2];
}
[[nodiscard]] bool operator!=(const CMatrix3f& other) const { return !operator==(other); }
void transpose();
CMatrix3f transposed() const;
[[nodiscard]] CMatrix3f transposed() const;
void invert() { *this = inverted(); }
CMatrix3f inverted() const;
[[nodiscard]] CMatrix3f inverted() const;
void addScaledMatrix(const CMatrix3f& other, float scale) {
CVector3f scaleVec(scale);
@ -116,28 +118,28 @@ public:
m[2] += other.m[2] * scaleVec;
}
static CMatrix3f RotateX(float theta) {
[[nodiscard]] static CMatrix3f RotateX(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
return CMatrix3f(simd<float>{1.f, 0.f, 0.f, 0.f}, simd<float>{0.f, cosT, sinT, 0.f},
simd<float>{0.f, -sinT, cosT, 0.f});
}
static CMatrix3f RotateY(float theta) {
[[nodiscard]] static CMatrix3f RotateY(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
return CMatrix3f(simd<float>{cosT, 0.f, -sinT, 0.f}, simd<float>{0.f, 1.f, 0.f, 0.f},
simd<float>{sinT, 0.f, cosT, 0.f});
}
static CMatrix3f RotateZ(float theta) {
[[nodiscard]] static CMatrix3f RotateZ(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
return CMatrix3f(simd<float>{cosT, sinT, 0.f, 0.f}, simd<float>{-sinT, cosT, 0.f, 0.f},
simd<float>{0.f, 0.f, 1.f, 0.f});
}
float determinant() const {
[[nodiscard]] float determinant() const {
return m[1][0] * (m[2][1] * m[0][2] - m[0][1] * m[2][2]) + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) +
m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
}
@ -145,7 +147,7 @@ public:
std::array<CVector3f, 3> m;
};
inline CMatrix3f operator*(const CMatrix3f& lhs, const CMatrix3f& rhs) {
[[nodiscard]] inline CMatrix3f operator*(const CMatrix3f& lhs, const CMatrix3f& rhs) {
std::array<simd<float>, 3> v;
for (size_t i = 0; i < v.size(); ++i) {
v[i] = lhs.m[0].mSimd * rhs[i].mSimd.shuffle<0, 0, 0, 0>() + lhs.m[1].mSimd * rhs[i].mSimd.shuffle<1, 1, 1, 1>() +

View File

@ -51,29 +51,29 @@ public:
constexpr CMatrix4f& operator=(const CMatrix4f& other) = default;
CVector4f operator*(const CVector4f& other) const {
[[nodiscard]] CVector4f operator*(const CVector4f& other) const {
return m[0].mSimd * other.mSimd.shuffle<0, 0, 0, 0>() + m[1].mSimd * other.mSimd.shuffle<1, 1, 1, 1>() +
m[2].mSimd * other.mSimd.shuffle<2, 2, 2, 2>() + m[3].mSimd * other.mSimd.shuffle<3, 3, 3, 3>();
}
CVector4f& operator[](size_t i) {
[[nodiscard]] CVector4f& operator[](size_t i) {
assert(i < m.size());
return m[i];
}
const CVector4f& operator[](size_t i) const {
[[nodiscard]] const CVector4f& operator[](size_t i) const {
assert(i < m.size());
return m[i];
}
CMatrix4f transposed() const;
[[nodiscard]] CMatrix4f transposed() const;
CVector3f multiplyOneOverW(const CVector3f& point) const {
[[nodiscard]] CVector3f multiplyOneOverW(const CVector3f& point) const {
CVector4f xfVec = *this * point;
return xfVec.toVec3f() / xfVec.w();
}
CVector3f multiplyOneOverW(const CVector3f& point, float& wOut) const {
[[nodiscard]] CVector3f multiplyOneOverW(const CVector3f& point, float& wOut) const {
CVector4f xfVec = *this * point;
wOut = xfVec.w();
return xfVec.toVec3f() / xfVec.w();
@ -83,7 +83,7 @@ public:
};
extern const CMatrix4f skIdentityMatrix4f;
inline CMatrix4f operator*(const CMatrix4f& lhs, const CMatrix4f& rhs) {
[[nodiscard]] inline CMatrix4f operator*(const CMatrix4f& lhs, const CMatrix4f& rhs) {
std::array<simd<float>, 4> v;
for (size_t i = 0; i < v.size(); ++i) {
v[i] = lhs.m[0].mSimd * rhs[i].mSimd.shuffle<0, 0, 0, 0>() + lhs.m[1].mSimd * rhs[i].mSimd.shuffle<1, 1, 1, 1>() +

View File

@ -18,7 +18,7 @@ public:
extents.readBig(in);
}
static COBBox ReadBig(athena::io::IStreamReader& in) {
[[nodiscard]] static COBBox ReadBig(athena::io::IStreamReader& in) {
COBBox out;
out.readBig(in);
return out;
@ -35,17 +35,19 @@ public:
constexpr COBBox(const CTransform& xf, const CVector3f& extents) : transform(xf), extents(extents) {}
CAABox calculateAABox(const CTransform& worldXf = CTransform()) const;
[[nodiscard]] CAABox calculateAABox(const CTransform& worldXf = CTransform()) const;
static COBBox FromAABox(const CAABox& box, const CTransform& xf) {
CVector3f center = box.center();
[[nodiscard]] static COBBox FromAABox(const CAABox& box, const CTransform& xf) {
const CVector3f center = box.center();
const CVector3f extents = box.max - center;
const CTransform newXf = xf * CTransform::Translate(center);
return COBBox(newXf, extents);
}
bool OBBIntersectsBox(const COBBox& other) const;
[[nodiscard]] bool OBBIntersectsBox(const COBBox& other) const;
bool AABoxIntersectsBox(const CAABox& other) const { return OBBIntersectsBox(FromAABox(other, CTransform())); }
[[nodiscard]] bool AABoxIntersectsBox(const CAABox& other) const {
return OBBIntersectsBox(FromAABox(other, CTransform()));
}
};
} // namespace zeus

View File

@ -23,9 +23,9 @@ public:
mSimd[3] = displacement;
}
float clipLineSegment(const CVector3f& a, const CVector3f& b) {
float mag = (b - a).dot(normal());
float dis = (-(y() - d())) / mag;
[[nodiscard]] float clipLineSegment(const CVector3f& a, const CVector3f& b) {
const float mag = (b - a).dot(normal());
const float dis = (-(y() - d())) / mag;
return clamp(0.0f, dis, 1.0f);
}
@ -38,31 +38,31 @@ public:
mSimd[3] = nd * mag;
}
float pointToPlaneDist(const CVector3f& pos) const { return pos.dot(normal()) - d(); }
[[nodiscard]] float pointToPlaneDist(const CVector3f& pos) const { return pos.dot(normal()) - d(); }
bool rayPlaneIntersection(const CVector3f& from, const CVector3f& to, CVector3f& point) const;
[[nodiscard]] bool rayPlaneIntersection(const CVector3f& from, const CVector3f& to, CVector3f& point) const;
CVector3f normal() const { return mSimd; }
[[nodiscard]] CVector3f normal() const { return mSimd; }
zeus::simd<float>::reference operator[](size_t idx) {
[[nodiscard]] zeus::simd<float>::reference operator[](size_t idx) {
assert(idx < 4);
return mSimd[idx];
}
float operator[](size_t idx) const {
[[nodiscard]] float operator[](size_t idx) const {
assert(idx < 4);
return mSimd[idx];
}
float x() const { return mSimd[0]; }
float y() const { return mSimd[1]; }
float z() const { return mSimd[2]; }
float d() const { return mSimd[3]; }
[[nodiscard]] float x() const { return mSimd[0]; }
[[nodiscard]] float y() const { return mSimd[1]; }
[[nodiscard]] float z() const { return mSimd[2]; }
[[nodiscard]] float d() const { return mSimd[3]; }
simd<float>::reference x() { return mSimd[0]; }
simd<float>::reference y() { return mSimd[1]; }
simd<float>::reference z() { return mSimd[2]; }
simd<float>::reference d() { return mSimd[3]; }
[[nodiscard]] simd<float>::reference x() { return mSimd[0]; }
[[nodiscard]] simd<float>::reference y() { return mSimd[1]; }
[[nodiscard]] simd<float>::reference z() { return mSimd[2]; }
[[nodiscard]] simd<float>::reference d() { return mSimd[3]; }
zeus::simd<float> mSimd;
};

View File

@ -63,9 +63,9 @@ public:
_updateCachedMatrix();
}
EProjType getType() const { return m_projType; }
[[nodiscard]] EProjType getType() const { return m_projType; }
const SProjOrtho& getOrtho() const {
[[nodiscard]] const SProjOrtho& getOrtho() const {
#ifndef NDEBUG
if (m_projType != EProjType::Orthographic) {
std::fprintf(stderr, "attempted to access orthographic structure of non-ortho projection");
@ -75,7 +75,7 @@ public:
return m_ortho;
}
const SProjPersp& getPersp() const {
[[nodiscard]] const SProjPersp& getPersp() const {
#ifndef NDEBUG
if (m_projType != EProjType::Perspective) {
std::fprintf(stderr, "attempted to access perspective structure of non-persp projection");
@ -85,7 +85,7 @@ public:
return m_persp;
}
const CMatrix4f& getCachedMatrix() const { return m_mtx; }
[[nodiscard]] const CMatrix4f& getCachedMatrix() const { return m_mtx; }
protected:
/* Projection type */

View File

@ -71,19 +71,19 @@ public:
return *this;
}
CQuaternion operator+(const CQuaternion& q) const { return mSimd + q.mSimd; }
[[nodiscard]] CQuaternion operator+(const CQuaternion& q) const { return mSimd + q.mSimd; }
CQuaternion operator-(const CQuaternion& q) const { return mSimd - q.mSimd; }
[[nodiscard]] CQuaternion operator-(const CQuaternion& q) const { return mSimd - q.mSimd; }
CQuaternion operator*(const CQuaternion& q) const;
[[nodiscard]] CQuaternion operator*(const CQuaternion& q) const;
CQuaternion operator/(const CQuaternion& q) const;
[[nodiscard]] CQuaternion operator/(const CQuaternion& q) const;
CQuaternion operator*(float scale) const { return mSimd * simd<float>(scale); }
[[nodiscard]] CQuaternion operator*(float scale) const { return mSimd * simd<float>(scale); }
CQuaternion operator/(float scale) const { return mSimd / simd<float>(scale); }
[[nodiscard]] CQuaternion operator/(float scale) const { return mSimd / simd<float>(scale); }
CQuaternion operator-() const { return -mSimd; }
[[nodiscard]] CQuaternion operator-() const { return -mSimd; }
const CQuaternion& operator+=(const CQuaternion& q) {
mSimd += q.mSimd;
@ -107,19 +107,19 @@ public:
return *this;
}
float magnitude() const { return std::sqrt(magSquared()); }
[[nodiscard]] float magnitude() const { return std::sqrt(magSquared()); }
float magSquared() const { return mSimd.dot4(mSimd); }
[[nodiscard]] float magSquared() const { return mSimd.dot4(mSimd); }
void normalize() { *this /= magnitude(); }
CQuaternion normalized() const { return *this / magnitude(); }
[[nodiscard]] CQuaternion normalized() const { return *this / magnitude(); }
static constexpr simd<float> InvertQuat = {1.f, -1.f, -1.f, -1.f};
void invert() { mSimd *= InvertQuat; }
CQuaternion inverse() const { return mSimd * InvertQuat; }
[[nodiscard]] CQuaternion inverse() const { return mSimd * InvertQuat; }
/**
* @brief Set the rotation using axis angle notation
@ -127,7 +127,7 @@ public:
* @param angle The magnitude of the rotation in radians
* @return
*/
static CQuaternion fromAxisAngle(const CUnitVector3f& axis, const CRelAngle& angle) {
[[nodiscard]] static CQuaternion fromAxisAngle(const CUnitVector3f& axis, const CRelAngle& angle) {
return CQuaternion(std::cos(angle / 2.f), axis * std::sin(angle / 2.f));
}
@ -137,93 +137,96 @@ public:
void rotateZ(const CRelAngle& angle) { *this *= fromAxisAngle({0.0f, 0.0f, 1.0f}, angle); }
static CVector3f rotate(const CQuaternion& rotation, const CAxisAngle& v) {
[[nodiscard]] static CVector3f rotate(const CQuaternion& rotation, const CAxisAngle& v) {
CQuaternion q = rotation * v;
q *= rotation.inverse();
return {q.mSimd.shuffle<1, 2, 3, 3>()};
}
static CQuaternion lookAt(const CUnitVector3f& source, const CUnitVector3f& dest, const CRelAngle& maxAng);
[[nodiscard]] static CQuaternion lookAt(const CUnitVector3f& source, const CUnitVector3f& dest,
const CRelAngle& maxAng);
CVector3f transform(const CVector3f& v) const {
CQuaternion r(0.f, v);
[[nodiscard]] CVector3f transform(const CVector3f& v) const {
const CQuaternion r(0.f, v);
return (*this * r * inverse()).getImaginary();
}
CQuaternion log() const;
[[nodiscard]] CQuaternion log() const;
CQuaternion exp() const;
[[nodiscard]] CQuaternion exp() const;
CTransform toTransform() const { return CTransform(CMatrix3f(*this)); }
[[nodiscard]] CTransform toTransform() const { return CTransform(CMatrix3f(*this)); }
CTransform toTransform(const zeus::CVector3f& origin) const { return CTransform(CMatrix3f(*this), origin); }
[[nodiscard]] CTransform toTransform(const zeus::CVector3f& origin) const {
return CTransform(CMatrix3f(*this), origin);
}
float dot(const CQuaternion& rhs) const { return mSimd.dot4(rhs.mSimd); }
[[nodiscard]] float dot(const CQuaternion& rhs) const { return mSimd.dot4(rhs.mSimd); }
static CQuaternion lerp(const CQuaternion& a, const CQuaternion& b, double t);
[[nodiscard]] static CQuaternion lerp(const CQuaternion& a, const CQuaternion& b, double t);
static CQuaternion slerp(const CQuaternion& a, const CQuaternion& b, double t);
[[nodiscard]] static CQuaternion slerp(const CQuaternion& a, const CQuaternion& b, double t);
static CQuaternion slerpShort(const CQuaternion& a, const CQuaternion& b, double t);
[[nodiscard]] static CQuaternion slerpShort(const CQuaternion& a, const CQuaternion& b, double t);
static CQuaternion nlerp(const CQuaternion& a, const CQuaternion& b, double t);
[[nodiscard]] static CQuaternion nlerp(const CQuaternion& a, const CQuaternion& b, double t);
static CQuaternion shortestRotationArc(const zeus::CVector3f& v0, const zeus::CVector3f& v1);
[[nodiscard]] static CQuaternion shortestRotationArc(const zeus::CVector3f& v0, const zeus::CVector3f& v1);
static CQuaternion clampedRotateTo(const zeus::CUnitVector3f& v0, const zeus::CUnitVector3f& v1,
const zeus::CRelAngle& angle);
[[nodiscard]] static CQuaternion clampedRotateTo(const zeus::CUnitVector3f& v0, const zeus::CUnitVector3f& v1,
const zeus::CRelAngle& angle);
float roll() const {
[[nodiscard]] float roll() const {
simd_floats f(mSimd);
return std::asin(-2.f * (f[1] * f[3] - f[0] * f[2]));
}
float pitch() const {
[[nodiscard]] float pitch() const {
simd_floats f(mSimd);
return std::atan2(2.f * (f[2] * f[3] + f[0] * f[1]), f[0] * f[0] - f[1] * f[1] - f[2] * f[2] + f[3] * f[3]);
}
float yaw() const {
[[nodiscard]] float yaw() const {
simd_floats f(mSimd);
return std::atan2(2.f * (f[1] * f[2] + f[0] * f[3]), f[0] * f[0] + f[1] * f[1] - f[2] * f[2] - f[3] * f[3]);
}
CQuaternion buildEquivalent() const;
[[nodiscard]] CQuaternion buildEquivalent() const;
zeus::CVector3f getImaginary() const { return mSimd.shuffle<1, 2, 3, 3>(); }
[[nodiscard]] CVector3f getImaginary() const { return mSimd.shuffle<1, 2, 3, 3>(); }
void setImaginary(const zeus::CVector3f& i) {
void setImaginary(const CVector3f& i) {
x() = i.x();
y() = i.y();
z() = i.z();
}
CRelAngle angleFrom(const zeus::CQuaternion& other) const;
[[nodiscard]] CRelAngle angleFrom(const CQuaternion& other) const;
simd<float>::reference operator[](size_t idx) {
[[nodiscard]] simd<float>::reference operator[](size_t idx) {
assert(idx < 4);
return mSimd[idx];
}
float operator[](size_t idx) const {
[[nodiscard]] float operator[](size_t idx) const {
assert(idx < 4);
return mSimd[idx];
}
float w() const { return mSimd[0]; }
float x() const { return mSimd[1]; }
float y() const { return mSimd[2]; }
float z() const { return mSimd[3]; }
[[nodiscard]] float w() const { return mSimd[0]; }
[[nodiscard]] float x() const { return mSimd[1]; }
[[nodiscard]] float y() const { return mSimd[2]; }
[[nodiscard]] float z() const { return mSimd[3]; }
simd<float>::reference w() { return mSimd[0]; }
simd<float>::reference x() { return mSimd[1]; }
simd<float>::reference y() { return mSimd[2]; }
simd<float>::reference z() { return mSimd[3]; }
[[nodiscard]] simd<float>::reference w() { return mSimd[0]; }
[[nodiscard]] simd<float>::reference x() { return mSimd[1]; }
[[nodiscard]] simd<float>::reference y() { return mSimd[2]; }
[[nodiscard]] simd<float>::reference z() { return mSimd[3]; }
simd<float> mSimd;
static CQuaternion fromNUQuaternion(const CNUQuaternion& q);
[[nodiscard]] static CQuaternion fromNUQuaternion(const CNUQuaternion& q);
};
/** Non-unit quaternion, no guarantee that it's normalized.
@ -243,52 +246,52 @@ public:
CNUQuaternion(const simd<float>& s) : mSimd(s) {}
static CNUQuaternion fromAxisAngle(const CUnitVector3f& axis, const CRelAngle& angle) {
[[nodiscard]] static CNUQuaternion fromAxisAngle(const CUnitVector3f& axis, const CRelAngle& angle) {
return CNUQuaternion(CQuaternion::fromAxisAngle(axis, angle));
}
float magnitude() const { return std::sqrt(magSquared()); }
[[nodiscard]] float magnitude() const { return std::sqrt(magSquared()); }
float magSquared() const { return mSimd.dot4(mSimd); }
[[nodiscard]] float magSquared() const { return mSimd.dot4(mSimd); }
void normalize() {
float magDiv = 1.f / magnitude();
mSimd *= magDiv;
}
CNUQuaternion normalized() const {
[[nodiscard]] CNUQuaternion normalized() const {
float magDiv = 1.f / magnitude();
return mSimd * simd<float>(magDiv);
}
CNUQuaternion operator*(const CNUQuaternion& q) const;
[[nodiscard]] CNUQuaternion operator*(const CNUQuaternion& q) const;
CNUQuaternion operator*(float f) const { return mSimd * simd<float>(f); }
[[nodiscard]] CNUQuaternion operator*(float f) const { return mSimd * simd<float>(f); }
const CNUQuaternion& operator+=(const CNUQuaternion& q) {
mSimd += q.mSimd;
return *this;
}
zeus::simd<float>::reference operator[](size_t idx) {
[[nodiscard]] simd<float>::reference operator[](size_t idx) {
assert(idx < 4);
return mSimd[idx];
}
float operator[](size_t idx) const {
[[nodiscard]] float operator[](size_t idx) const {
assert(idx < 4);
return mSimd[idx];
}
float w() const { return mSimd[0]; }
float x() const { return mSimd[1]; }
float y() const { return mSimd[2]; }
float z() const { return mSimd[3]; }
[[nodiscard]] float w() const { return mSimd[0]; }
[[nodiscard]] float x() const { return mSimd[1]; }
[[nodiscard]] float y() const { return mSimd[2]; }
[[nodiscard]] float z() const { return mSimd[3]; }
simd<float>::reference w() { return mSimd[0]; }
simd<float>::reference x() { return mSimd[1]; }
simd<float>::reference y() { return mSimd[2]; }
simd<float>::reference z() { return mSimd[3]; }
[[nodiscard]] simd<float>::reference w() { return mSimd[0]; }
[[nodiscard]] simd<float>::reference x() { return mSimd[1]; }
[[nodiscard]] simd<float>::reference y() { return mSimd[2]; }
[[nodiscard]] simd<float>::reference z() { return mSimd[3]; }
simd<float> mSimd;
};
@ -298,11 +301,11 @@ inline CQuaternion CQuaternion::fromNUQuaternion(const CNUQuaternion& q) {
return norm.mSimd;
}
CQuaternion operator+(float lhs, const CQuaternion& rhs);
[[nodiscard]] CQuaternion operator+(float lhs, const CQuaternion& rhs);
CQuaternion operator-(float lhs, const CQuaternion& rhs);
[[nodiscard]] CQuaternion operator-(float lhs, const CQuaternion& rhs);
CQuaternion operator*(float lhs, const CQuaternion& rhs);
[[nodiscard]] CQuaternion operator*(float lhs, const CQuaternion& rhs);
CNUQuaternion operator*(float lhs, const CNUQuaternion& rhs);
[[nodiscard]] CNUQuaternion operator*(float lhs, const CNUQuaternion& rhs);
} // namespace zeus

View File

@ -9,7 +9,7 @@ public:
constexpr CRectangle(float x, float y, float w, float h) : position(x, y), size(w, h) {}
bool contains(const CVector2f& point) const {
[[nodiscard]] bool contains(const CVector2f& point) const {
if (point.x() < position.x() || point.x() > position.x() + size.x())
return false;
if (point.y() < position.y() || point.y() > position.y() + size.y())
@ -18,7 +18,7 @@ public:
return true;
}
bool intersects(const CRectangle& rect) const {
[[nodiscard]] bool intersects(const CRectangle& rect) const {
return !(position.x() > rect.position.x() + rect.size.x() || rect.position.x() > position.x() + size.x() ||
position.y() > rect.position.y() + rect.size.y() || rect.position.y() > position.y() + size.y());
}

View File

@ -12,7 +12,7 @@ class CRelAngle {
float angle = 0.f;
public:
static float MakeRelativeAngle(float angle) noexcept {
[[nodiscard]] static float MakeRelativeAngle(float angle) noexcept {
float ret = angle - std::trunc(angle / (2.f * M_PIF)) * (2.f * M_PIF);
if (ret < 0.f)
ret += 2.f * M_PIF;
@ -32,13 +32,13 @@ public:
constexpr CRelAngle& operator=(const CRelAngle& ang) noexcept = default;
constexpr float asDegrees() const noexcept { return radToDeg(angle); }
[[nodiscard]] constexpr float asDegrees() const noexcept { return radToDeg(angle); }
constexpr float asRadians() const noexcept { return angle; }
[[nodiscard]] constexpr float asRadians() const noexcept { return angle; }
float arcCosine() const noexcept { return std::acos(angle); }
[[nodiscard]] float arcCosine() const noexcept { return std::acos(angle); }
static constexpr CRelAngle FromDegrees(float angle) noexcept {
[[nodiscard]] static constexpr CRelAngle FromDegrees(float angle) noexcept {
CRelAngle ret;
ret.angle = degToRad(angle);
return ret;
@ -46,9 +46,9 @@ public:
constexpr operator float() const noexcept { return angle; }
static constexpr CRelAngle FromRadians(float angle) noexcept { return CRelAngle(angle); }
[[nodiscard]] static constexpr CRelAngle FromRadians(float angle) noexcept { return CRelAngle(angle); }
constexpr bool operator<(const CRelAngle& other) const noexcept { return angle < other.angle; }
[[nodiscard]] constexpr bool operator<(const CRelAngle& other) const noexcept { return angle < other.angle; }
constexpr CRelAngle& operator+=(const CRelAngle& other) noexcept {
angle += other.angle;
@ -92,6 +92,6 @@ public:
void makeRel() noexcept { angle = MakeRelativeAngle(angle); }
CRelAngle asRel() const noexcept { return CRelAngle(MakeRelativeAngle(angle)); }
[[nodiscard]] CRelAngle asRel() const noexcept { return CRelAngle(MakeRelativeAngle(angle)); }
};
} // namespace zeus

View File

@ -7,10 +7,10 @@ class CSphere {
public:
constexpr CSphere(const CVector3f& position, float radius) : position(position), radius(radius) {}
CVector3f getSurfaceNormal(const CVector3f& coord) const { return (coord - position).normalized(); }
[[nodiscard]] CVector3f getSurfaceNormal(const CVector3f& coord) const { return (coord - position).normalized(); }
bool intersects(const CSphere& other) const {
float dist = (position - other.position).magnitude();
[[nodiscard]] bool intersects(const CSphere& other) const {
const float dist = (position - other.position).magnitude();
return dist < (radius + other.radius);
}

View File

@ -37,22 +37,26 @@ public:
constexpr CTransform(const CVector3f& c0, const CVector3f& c1, const CVector3f& c2, const CVector3f& c3)
: basis(c0, c1, c2), origin(c3) {}
bool operator==(const CTransform& other) const { return origin == other.origin && basis == other.basis; }
[[nodiscard]] bool operator==(const CTransform& other) const {
return origin == other.origin && basis == other.basis;
}
CTransform operator*(const CTransform& rhs) const {
[[nodiscard]] bool operator!=(const CTransform& other) const { return !operator==(other); }
[[nodiscard]] CTransform operator*(const CTransform& rhs) const {
return CTransform(basis * rhs.basis, origin + (basis * rhs.origin));
}
CTransform inverse() const {
[[nodiscard]] CTransform inverse() const {
CMatrix3f inv = basis.inverted();
return CTransform(inv, inv * -origin);
}
static CTransform Translate(const CVector3f& position) { return {CMatrix3f(), position}; }
[[nodiscard]] static CTransform Translate(const CVector3f& position) { return {CMatrix3f(), position}; }
static CTransform Translate(float x, float y, float z) { return Translate({x, y, z}); }
[[nodiscard]] static CTransform Translate(float x, float y, float z) { return Translate({x, y, z}); }
CTransform operator+(const CVector3f& other) const { return CTransform(basis, origin + other); }
[[nodiscard]] CTransform operator+(const CVector3f& other) const { return CTransform(basis, origin + other); }
CTransform& operator+=(const CVector3f& other) {
origin += other;
@ -66,25 +70,25 @@ public:
return *this;
}
zeus::CVector3f rotate(const CVector3f& vec) const { return basis * vec; }
[[nodiscard]] CVector3f rotate(const CVector3f& vec) const { return basis * vec; }
static CTransform RotateX(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
[[nodiscard]] static CTransform RotateX(float theta) {
const float sinT = std::sin(theta);
const float cosT = std::cos(theta);
return CTransform(CMatrix3f(simd<float>{1.f, 0.f, 0.f, 0.f}, simd<float>{0.f, cosT, sinT, 0.f},
simd<float>{0.f, -sinT, cosT, 0.f}));
}
static CTransform RotateY(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
[[nodiscard]] static CTransform RotateY(float theta) {
const float sinT = std::sin(theta);
const float cosT = std::cos(theta);
return CTransform(CMatrix3f(simd<float>{cosT, 0.f, -sinT, 0.f}, simd<float>{0.f, 1.f, 0.f, 0.f},
simd<float>{sinT, 0.f, cosT, 0.f}));
}
static CTransform RotateZ(float theta) {
float sinT = std::sin(theta);
float cosT = std::cos(theta);
[[nodiscard]] static CTransform RotateZ(float theta) {
const float sinT = std::sin(theta);
const float cosT = std::cos(theta);
return CTransform(CMatrix3f(simd<float>{cosT, sinT, 0.f, 0.f}, simd<float>{-sinT, cosT, 0.f, 0.f},
simd<float>{0.f, 0.f, 1.f, 0.f}));
}
@ -134,7 +138,7 @@ public:
basis[1] -= b0;
}
CVector3f transposeRotate(const CVector3f& in) const {
[[nodiscard]] CVector3f transposeRotate(const CVector3f& in) const {
return CVector3f(basis[0].dot(in), basis[1].dot(in), basis[2].dot(in));
}
@ -143,26 +147,26 @@ public:
*this = *this * xfrm;
}
static CTransform Scale(const CVector3f& factor) {
[[nodiscard]] static CTransform Scale(const CVector3f& factor) {
return CTransform(CMatrix3f(simd<float>{factor.x(), 0.f, 0.f, 0.f}, simd<float>{0.f, factor.y(), 0.f, 0.f},
simd<float>{0.f, 0.f, factor.z(), 0.f}));
}
static CTransform Scale(float x, float y, float z) {
[[nodiscard]] static CTransform Scale(float x, float y, float z) {
return CTransform(
CMatrix3f(simd<float>{x, 0.f, 0.f, 0.f}, simd<float>{0.f, y, 0.f, 0.f}, simd<float>{0.f, 0.f, z, 0.f}));
}
static CTransform Scale(float factor) {
[[nodiscard]] static CTransform Scale(float factor) {
return CTransform(CMatrix3f(simd<float>{factor, 0.f, 0.f, 0.f}, simd<float>{0.f, factor, 0.f, 0.f},
simd<float>{0.f, 0.f, factor, 0.f}));
}
CTransform multiplyIgnoreTranslation(const CTransform& rhs) const {
[[nodiscard]] CTransform multiplyIgnoreTranslation(const CTransform& rhs) const {
return CTransform(basis * rhs.basis, origin + rhs.origin);
}
CTransform getRotation() const {
[[nodiscard]] CTransform getRotation() const {
CTransform ret = *this;
ret.origin.zeroOut();
return ret;
@ -177,11 +181,11 @@ public:
* buildMatrix3f is here for compliance with Retro's Math API
* @return The Matrix (Neo, you are the one)
*/
const CMatrix3f& buildMatrix3f() const { return basis; }
[[nodiscard]] const CMatrix3f& buildMatrix3f() const { return basis; }
CVector3f operator*(const CVector3f& other) const { return origin + basis * other; }
[[nodiscard]] CVector3f operator*(const CVector3f& other) const { return origin + basis * other; }
CMatrix4f toMatrix4f() const {
[[nodiscard]] CMatrix4f toMatrix4f() const {
CMatrix4f ret(basis[0], basis[1], basis[2], origin);
ret[0][3] = 0.0f;
ret[1][3] = 0.0f;
@ -190,11 +194,11 @@ public:
return ret;
}
CVector3f upVector() const { return basis.m[2]; }
[[nodiscard]] CVector3f upVector() const { return basis.m[2]; }
CVector3f frontVector() const { return basis.m[1]; }
[[nodiscard]] CVector3f frontVector() const { return basis.m[1]; }
CVector3f rightVector() const { return basis.m[0]; }
[[nodiscard]] CVector3f rightVector() const { return basis.m[0]; }
void orthonormalize() {
basis[0].normalize();
@ -213,7 +217,7 @@ public: