From 2d5e34316c5dd50e7d366eea9b738b4989313496 Mon Sep 17 00:00:00 2001 From: Borealis Date: Thu, 9 Jan 2025 18:08:31 +0000 Subject: [PATCH] Auto-update from libvoxelstorm: latest vectorstorm improvements from Armchair planet engine (ae38361) --- vectorstorm/aabb/aabb2.h | 31 ++++--- vectorstorm/aabb/aabb3.h | 33 +++++--- vectorstorm/matrix/matrix3.h | 125 +++++++++++++++++++--------- vectorstorm/matrix/matrix4.h | 94 ++++++++++++++++----- vectorstorm/quat/quat.h | 153 +++++++++++++++++------------------ vectorstorm/sqrt_fast.h | 36 +++++++++ vectorstorm/vector/vector2.h | 106 ++++++++++++------------ vectorstorm/vector/vector3.h | 105 +++++++++++++++--------- vectorstorm/vector/vector4.h | 99 +++++++++++++---------- 9 files changed, 484 insertions(+), 298 deletions(-) diff --git a/vectorstorm/aabb/aabb2.h b/vectorstorm/aabb/aabb2.h index c00d637..8c71e66 100644 --- a/vectorstorm/aabb/aabb2.h +++ b/vectorstorm/aabb/aabb2.h @@ -140,6 +140,7 @@ class aabb2 { * bounding box becomes valid and contains solely the source point or bounding-box respectively. * @return True if box is valid, otherwise false */ + [[nodiscard]] inline bool constexpr valid() const noexcept __attribute__((__always_inline__)) { return min.x <= max.x && min.y <= max.y; } @@ -187,7 +188,7 @@ class aabb2 { * @param point A point to extend the box by. * @return Copy of extended bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb2 extended(vector2 const &point) const noexcept { aabb2 ret(*this); ret.extend(point); @@ -199,7 +200,7 @@ class aabb2 { * @param box A box to extend the copy by. * @return Copy of extended bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb2 extended(aabb2 const &box) const noexcept { aabb2 ret(*this); ret.extend(box); @@ -211,7 +212,7 @@ class aabb2 { * @param point A point to be tested. * @return True if point @a point lies within bounding-box, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr intersects(vector2 const &point) const noexcept { return min.x <= point.x && point.x <= max.x && min.y <= point.y && point.y <= max.y; @@ -222,7 +223,7 @@ class aabb2 { * @param box A box to be tested for intersection. * @return True if there's intersection between boxes, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr intersects(aabb2 const &box) const noexcept { return max.x >= box.min.x && min.x <= box.max.x && max.y >= box.min.y && min.y <= box.max.y; @@ -235,7 +236,7 @@ class aabb2 { * @return Result of intersection. * @see valid() method for more information on invalid bounding-boxes. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb2 intersection(aabb2 const &other) const noexcept { return intersects(other) ? aabb2(std::max(min, other.min), std::min(max, other.max)) : aabb2{}; } @@ -246,7 +247,7 @@ class aabb2 { * @param ray The intersecting ray; does not need to be normalised * @return True if the ray intersects the box, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr ray_intersects(vector2 const &ray, vector2 const &origin = vector2()) const noexcept { // adapted from http://tavianator.com/2011/05/fast-branchless-raybounding-box-intersections/ /* @@ -277,6 +278,7 @@ class aabb2 { * Gets centre point of bounding box. * @return The centre point of the bounding box. */ + [[nodiscard]] inline constexpr vector2 centre() const noexcept __attribute__((__always_inline__)) { return (min + max) / static_cast(2); } @@ -285,6 +287,7 @@ class aabb2 { * Gets extent of bounding-box. * @return Extent of bounding-box. */ + [[nodiscard]] inline constexpr vector2 extent() const noexcept __attribute__((__always_inline__)) { return (max - min) / static_cast(2); } @@ -293,6 +296,7 @@ class aabb2 { * Gets diagonal size of bounding-box * @return Sizes for particular dimensions. */ + [[nodiscard]] inline constexpr vector2 size() const noexcept __attribute__((__always_inline__)) { return max - min; } @@ -308,6 +312,7 @@ class aabb2 { * 4. (@c - @c - @c +) * */ + [[nodiscard]] inline constexpr vector2 point(unsigned int i) const noexcept __attribute__((__always_inline__)) { return vector2((i & 1) ? min.x : max.x, (i & 2) ? min.y : max.y); @@ -321,7 +326,7 @@ class aabb2 { * @param rhs Right-hand side. * @return True if @a rhs and this bounding-boxes are equal, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr operator==(aabb2 const &rhs) const noexcept { return min == rhs.min && max == rhs.max; } @@ -331,7 +336,7 @@ class aabb2 { * @param rhs Right-hand side. * @return True if @a rhs and this bounding-boxes are not equal, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr operator!=(aabb2 const &rhs) const noexcept { return min != rhs.min || max != rhs.max; } @@ -341,7 +346,7 @@ class aabb2 { * @param rhs A vector to move this bounding-box by. * @return A resulting moved bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb2 constexpr operator+(vector2 const &rhs) const noexcept { return aabb2( vector2{min.x + rhs.x, min.y + rhs.y}, @@ -354,7 +359,7 @@ class aabb2 { * @param rhs A vector to move this bounding-box by the inverse of. * @return A resulting moved bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb2 constexpr operator-(vector2 const &rhs) const noexcept { return aabb2( vector2{min.x - rhs.x, min.y - rhs.y}, @@ -367,7 +372,7 @@ class aabb2 { * @param rhs A vector to move this bounding-box by. * @return Reference to this. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb2 constexpr &operator+=(vector2 const &rhs) noexcept { min.x += rhs.x; min.y += rhs.y; @@ -417,7 +422,7 @@ class aabb2 { * @param rhs Right-hand side of union. * @return A resulting bounding-box representing union. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb2 constexpr operator|(aabb2 const &rhs) const noexcept { return extended(rhs); } @@ -427,7 +432,7 @@ class aabb2 { * @param rhs Right-hand side. * @return Resulting bounding-box representing the intersection. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb2 constexpr operator&(aabb2 const &rhs) const noexcept { return intersection(rhs); } diff --git a/vectorstorm/aabb/aabb3.h b/vectorstorm/aabb/aabb3.h index 59be4f0..5cbc9b7 100644 --- a/vectorstorm/aabb/aabb3.h +++ b/vectorstorm/aabb/aabb3.h @@ -145,6 +145,7 @@ class aabb3 { * bounding box becomes valid and contains solely the source point or bounding-box respectively. * @return True if box is valid, otherwise false */ + [[nodiscard]] inline bool constexpr valid() const noexcept __attribute__((__always_inline__)) { return min.x <= max.x && min.y <= max.y && min.z <= max.z; } @@ -192,7 +193,7 @@ class aabb3 { * @param point A point to extend the box by. * @return Copy of extended bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb3 extended(vector3 const &point) const noexcept { aabb3 ret(*this); ret.extend(point); @@ -204,7 +205,7 @@ class aabb3 { * @param box A box to extend the copy by. * @return Copy of extended bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb3 extended(aabb3 const &box) const noexcept { aabb3 ret(*this); ret.extend(box); @@ -216,7 +217,7 @@ class aabb3 { * @param point A point to be tested. * @return True if point @a point lies within bounding-box, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr intersects(vector3 const &point) const noexcept { return min.x <= point.x && point.x <= max.x && min.y <= point.y && point.y <= max.y && @@ -228,7 +229,7 @@ class aabb3 { * @param box A box to be tested for intersection. * @return True if there's intersection between boxes, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr intersects(aabb3 const &box) const noexcept { return max.x >= box.min.x && min.x <= box.max.x && max.y >= box.min.y && min.y <= box.max.y && @@ -242,7 +243,7 @@ class aabb3 { * @return Result of intersection. * @see valid() method for more information on invalid bounding-boxes. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline constexpr aabb3 intersection(aabb3 const &other) const noexcept { return intersects(other) ? aabb3(std::max(min, other.min), std::min(max, other.max)) : aabb3{}; } @@ -253,7 +254,7 @@ class aabb3 { * @param origin Origin of the intersecting ray * @return True if the ray intersects the box, otherwise false. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr ray_intersects(vector3 const &ray, vector3 const &origin = vector3()) const noexcept { // adapted from http://tavianator.com/2011/05/fast-branchless-raybounding-box-intersections/ /* @@ -293,6 +294,7 @@ class aabb3 { * Gets centre point of bounding box. * @return The centre point of the bounding box. */ + [[nodiscard]] inline vector3 constexpr centre() const noexcept __attribute__((__always_inline__)) { return (min + max) / static_cast(2); } @@ -301,6 +303,7 @@ class aabb3 { * Gets extent of bounding-box. * @return Extent of bounding-box. */ + [[nodiscard]] inline vector3 constexpr extent() const noexcept __attribute__((__always_inline__)) { return (max - min) / static_cast(2); } @@ -309,6 +312,7 @@ class aabb3 { * Gets diagonal size of bounding-box * @return Sizes for particular dimensions. */ + [[nodiscard]] inline vector3 constexpr size() const noexcept __attribute__((__always_inline__)) { return max - min; } @@ -328,6 +332,7 @@ class aabb3 { * 8. (@c - @c - @c -) * */ + [[nodiscard]] inline vector3 constexpr point(unsigned int i) const noexcept __attribute__((__always_inline__)) { return vector3((i & 1) ? min.x : max.x, (i & 2) ? min.y : max.y, @@ -339,9 +344,10 @@ class aabb3 { * @param t A transform matrix * @return Transformed bounding-box */ + [[nodiscard]] inline aabb3 constexpr transformed(matrix4 const &t) const noexcept __attribute__((__always_inline__)) { aabb3 ret; - for(unsigned int i = 0; i != 8; ++i) { + for(unsigned int i{0}; i != 8; ++i) { const vector4 p(point(i), 1); ret.extend((t * p).xyz()); } @@ -356,7 +362,7 @@ class aabb3 { * @param rhs Right-hand side * @return True if @a rhs and this bounding-boxes are equal, otherwise false */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr operator==(aabb3 const &rhs) const noexcept { return min == rhs.min && max == rhs.max; } @@ -366,7 +372,7 @@ class aabb3 { * @param rhs Right-hand side * @return True if @a rhs and this bounding-boxes are not equal, otherwise false */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr operator!=(aabb3 const &rhs) const noexcept { return min != rhs.min || max != rhs.max; } @@ -376,7 +382,7 @@ class aabb3 { * @param rhs A vector to move this bounding-box by. * @return A resulting moved bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb3 constexpr operator+(vector3 const &rhs) const noexcept { return aabb3( vector3{min.x + rhs.x, min.y + rhs.y, min.z + rhs.z}, @@ -389,7 +395,7 @@ class aabb3 { * @param rhs A vector to move this bounding-box by the inverse of. * @return A resulting moved bounding-box. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb3 constexpr operator-(vector3 const &rhs) const noexcept { return aabb3( vector3{min.x - rhs.x, min.y - rhs.y, min.z - rhs.z}, @@ -434,6 +440,7 @@ class aabb3 { * @param rhs matrix 4x4 representing the transform. * @return Transformed bounding-box. */ + [[nodiscard]] inline aabb3 constexpr operator*(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return transformed(rhs); } @@ -475,7 +482,7 @@ class aabb3 { * @param rhs Right-hand side of union. * @return A resulting bounding-box representing union. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb3 constexpr operator|(aabb3 const &rhs) const noexcept { return extended(rhs); } @@ -485,7 +492,7 @@ class aabb3 { * @param rhs Right-hand side. * @return Resulting bounding-box representing the intersection. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline aabb3 constexpr operator&(aabb3 const &rhs) const noexcept { return intersection(rhs); } diff --git a/vectorstorm/matrix/matrix3.h b/vectorstorm/matrix/matrix3.h index f45e9c6..d637c7b 100644 --- a/vectorstorm/matrix/matrix3.h +++ b/vectorstorm/matrix/matrix3.h @@ -138,6 +138,7 @@ class matrix3 { * @param yDeg Angle (in degrees) of rotation around axis Y. * @param zDeg Angle (in degrees) of rotation around axis Z. */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_from_euler_angles(T xDeg, T yDeg, T zDeg) noexcept __attribute__((__always_inline__)) { return create_rotation_from_euler_angles_rad(deg2rad(xDeg), deg2rad(yDeg), deg2rad(zDeg)); } @@ -148,6 +149,7 @@ class matrix3 { * @param yRads Angle (in radians) of rotation around axis Y. * @param zRads Angle (in radians) of rotation around axis Z. */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_from_euler_angles_rad(T xRads, T yRads, T zRads) noexcept __attribute__((__always_inline__)) { // adapted from Inigo Quilez: http://www.iquilezles.org/www/articles/noacos/noacos.htm //T sin_xRads, cos_xRads, sin_yRads, cos_yRads, sin_zRads, cos_zRads; @@ -183,6 +185,7 @@ class matrix3 { * @param axis Axis to rotate around. * @param angle Angle (in degrees) of rotation around axis. */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_around_axis(vector3 const &axis, T angle) noexcept __attribute__((__always_inline__)) { return create_rotation_around_axis_rad(axis, deg2rad(angle)); } @@ -192,6 +195,7 @@ class matrix3 { * @param axis Axis to rotate around. * @param angle Angle (in radians) of rotation around axis. */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_around_axis_rad(vector3 const &axis, T angle) noexcept __attribute__((__always_inline__)) { // adapted from Inigo Quilez: http://www.iquilezles.org/www/articles/noacos/noacos.htm // zero-initialisation is required for gcc not to complain when the function is constexpr @@ -220,6 +224,7 @@ class matrix3 { * @param to Vector to rotate to. * @return An instance of matrix3 representing rotation between the two vectors. */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_between_vectors(vector3 const &from, vector3 const &to) noexcept __attribute__((__always_inline__)) { // the static cast is to avoid narrowing conversion warnings when used with ints vector3 const cross(to.cross(from)); @@ -249,6 +254,7 @@ class matrix3 { * @param up_dir Direction of up vector * @return Resulting matrix that's oriented to the target vector */ + [[nodiscard]] inline static matrix3 constexpr create_rotation_aligned_to_vector(vector3 const &target, vector3 const &up_dir) noexcept __attribute__((__always_inline__)) { vector3 const forward{target.normalise_copy()}; vector3 const side{forward.cross(up_dir).normalise_safe_copy()}; // Side = forward x up @@ -270,7 +276,7 @@ class matrix3 { /** * Creates rotation matrix from ODE matrix. */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix3 constexpr from_ode(It const *mat) noexcept { return matrix3(static_cast(mat[0]), static_cast(mat[4]), static_cast(mat[8]), static_cast(mat[1]), static_cast(mat[5]), static_cast(mat[9]), @@ -283,7 +289,7 @@ class matrix3 { * @param arr An array of elements for 3x3 matrix in row major order. * @return An instance of matrix3 representing @a arr */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix3 constexpr from_row_major_array(FromT const *arr) noexcept { return matrix3(static_cast(arr[0]), static_cast(arr[3]), static_cast(arr[6]), static_cast(arr[1]), static_cast(arr[4]), static_cast(arr[7]), @@ -296,7 +302,7 @@ class matrix3 { * @param arr An array of elements for 3x3 matrix in column major order. * @return An instance of matrix3 representing @a arr */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix3 constexpr from_column_major_array(FromT const *arr) noexcept { return matrix3(static_cast(arr[0]), static_cast(arr[1]), static_cast(arr[2]), static_cast(arr[3]), static_cast(arr[4]), static_cast(arr[5]), @@ -312,6 +318,7 @@ class matrix3 { * | lhs[i] - rhs[i] | < epsilon, * same for y-coordinate, z-coordinate, and w-coordinate. */ + [[nodiscard]] inline bool constexpr operator==(matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return std::abs(data[0] - rhs.data[0]) < epsilon && @@ -342,8 +349,9 @@ class matrix3 { /** * Inequality test operator * @param rhs Right hand side argument of binary operator. - * @return not (lhs == rhs) :-P + * @return not (lhs == rhs) */ + [[nodiscard]] inline bool constexpr operator!=(matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } @@ -354,16 +362,39 @@ class matrix3 { * @param x Number of column (0..2) * @param y Number of row (0..2) */ - inline T constexpr &at(int x, int y) noexcept __attribute__((__always_inline__)) { + [[nodiscard]] + inline T constexpr &operator[](unsigned int x, unsigned int y) noexcept __attribute__((__always_inline__)) { + return data[x * 3 + y]; + } + /** + * Get reference to element at position (x,y). + * @param x Number of column (0..2) + * @param y Number of row (0..2) + */ + [[nodiscard]] + inline T constexpr const &operator[](unsigned int x, unsigned int y) const noexcept __attribute__((__always_inline__)) { + return data[x * 3 + y]; + } + + /** + * Get reference to element at position (x,y). Throws an exception if out of range. + * @param x Number of column (0..2) + * @param y Number of row (0..2) + */ + [[nodiscard]] + inline T constexpr &at(unsigned int x, unsigned int y) noexcept __attribute__((__always_inline__)) { + if(x > 2 || y > 2) throw std::out_of_range("Matrix access at() function accepts x and y values 0..2, given " + std::to_string(x) + ", " + std::to_string(y)); return data[x * 3 + y]; } /** - * Get constant reference to element at position (x,y). + * Get constant reference to element at position (x,y). Throws an exception if out of range. * @param x Number of column (0..2) * @param y Number of row (0..2) */ - inline T constexpr const &at(int x, int y) const noexcept __attribute__((__always_inline__)) { + [[nodiscard]] + inline T constexpr const &at(unsigned int x, unsigned int y) const noexcept __attribute__((__always_inline__)) { + if(x > 2 || y > 2) throw std::out_of_range("Matrix access at() function accepts x and y values 0..2, given " + std::to_string(x) + ", " + std::to_string(y)); return data[x * 3 + y]; } @@ -372,8 +403,10 @@ class matrix3 { * @param i Number of row (1..3) * @param j Number of column (1..3) */ - inline T constexpr &operator()(int i, int j) noexcept __attribute__((__always_inline__)) { - return data[(j - 1) * 3 + i - 1]; + [[nodiscard]] [[deprecated("Use either multidimensional operator[] or .at(), counting from 0")]] + inline T constexpr &operator()(unsigned int i, unsigned int j) noexcept __attribute__((__always_inline__)) { + assert(j != 0 && j < 4); + return operator[](j - 1, i - 1); } /** @@ -381,13 +414,16 @@ class matrix3 { * @param i Number of row (1..3) * @param j Number of column (1..3) */ - inline T constexpr const &operator()(int i, int j) const noexcept __attribute__((__always_inline__)) { - return data[(j - 1) * 3 + i - 1]; + [[nodiscard]] [[deprecated("Use either multidimensional operator[] or .at(), counting from 0")]] + inline T constexpr const &operator()(unsigned int i, unsigned int j) const noexcept __attribute__((__always_inline__)) { + assert(j != 0 && j < 4); + return operator[](j - 1, i - 1); } /** * Returns transform (4x4) matrix including this as the rotation component. */ + [[nodiscard]] inline matrix4 constexpr get_transform() const noexcept __attribute__((__always_inline__)) { return matrix4(data[0], data[1], data[2], static_cast(0), data[3], data[4], data[5], static_cast(0), @@ -428,7 +464,7 @@ class matrix3 { */ inline matrix3 constexpr &operator=(T const *rhs) noexcept __attribute__((__always_inline__)) { /* - for(int i = 0; i != 9; ++i) { + for(unsigned int i{0}; i != 9; ++i) { data[i] = (T)rhs[i]; } */ @@ -468,6 +504,7 @@ class matrix3 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator+(matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] + rhs.data[0], data[1] + rhs.data[1], data[2] + rhs.data[2], data[3] + rhs.data[3], data[4] + rhs.data[4], data[5] + rhs.data[5], @@ -478,6 +515,7 @@ class matrix3 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator-(matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] - rhs.data[0], data[1] - rhs.data[1], data[2] - rhs.data[2], data[3] - rhs.data[3], data[4] - rhs.data[4], data[5] - rhs.data[5], @@ -489,6 +527,7 @@ class matrix3 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator+(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] + rhs, data[1] + rhs, data[2] + rhs, data[3] + rhs, data[4] + rhs, data[5] + rhs, @@ -499,6 +538,7 @@ class matrix3 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator-(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] - rhs, data[1] - rhs, data[2] - rhs, data[3] - rhs, data[4] - rhs, data[5] - rhs, @@ -510,6 +550,7 @@ class matrix3 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] * rhs, data[1] * rhs, data[2] * rhs, data[3] * rhs, data[4] * rhs, data[5] * rhs, @@ -520,6 +561,7 @@ class matrix3 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(data[0] / rhs, data[1] / rhs, data[2] / rhs, data[3] / rhs, data[4] / rhs, data[5] / rhs, @@ -567,6 +609,7 @@ class matrix3 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(data[0] * rhs.x + data[3] * rhs.y + data[6] * rhs.z, data[1] * rhs.x + data[4] * rhs.y + data[7] * rhs.z, @@ -578,6 +621,7 @@ class matrix3 { * @param rhs Right hand side argument of binary operator. * Enabling vector4 rotation as if it's a vector3, maintaining W */ + [[nodiscard]] inline vector4 constexpr operator*(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(data[0] * rhs.x + data[3] * rhs.y + data[6] * rhs.z, data[1] * rhs.x + data[4] * rhs.y + data[7] * rhs.z, @@ -589,6 +633,7 @@ class matrix3 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix3 constexpr operator*(matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix3(rhs.data[0] * data[0] + rhs.data[1] * data[3] + rhs.data[2] * data[6], rhs.data[0] * data[1] + rhs.data[1] * data[4] + rhs.data[2] * data[7], @@ -616,6 +661,7 @@ class matrix3 { /** * Transpose matrix. */ + [[nodiscard("Transpose does not modify the input matrix")]] inline matrix3 constexpr transpose() const noexcept __attribute__((__always_inline__)) { return matrix3(data[0], data[3], data[6], data[1], data[4], data[7], @@ -631,6 +677,7 @@ class matrix3 { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input matrix")]] inline matrix3 constexpr lerp(T fact, matrix3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (*this) + (rhs - (*this)) * fact; } @@ -644,6 +691,7 @@ class matrix3 { * Computes inverse matrix * @return Inverse matrix of this matrix. */ + [[nodiscard("Inverse does not modify the input matrix")]] inline matrix3 constexpr inverse() const noexcept __attribute__((__always_inline__)) { return matrix3(data[4] * data[8] - data[7] * data[5], data[7] * data[2] - data[1] * data[8], @@ -662,9 +710,10 @@ class matrix3 { * 2. normalises the tangent and makes sure it is orthogonal to normal. * 3. normalises binormal and makes sure it is orthogonal to both normal and tangent. */ + template inline void constexpr orthonormalise() noexcept __attribute__((__always_inline__)) { // normalize x: - T const x_length = static_cast(std::sqrt(data[0] * data[0] + data[1] * data[1] + data[2] * data[2])); + T const x_length{static_cast(sqrt_switchable(data[0] * data[0] + data[1] * data[1] + data[2] * data[2]))}; data[0] /= x_length; data[1] /= x_length; data[2] /= x_length; @@ -674,7 +723,7 @@ class matrix3 { data[7] -= data[7] * x_dot_z; data[8] -= data[8] * x_dot_z; // normalize z: - T const z_length = static_cast(std::sqrt(data[6] * data[6] + data[7] * data[7] + data[8] * data[8])); + T const z_length{static_cast(sqrt_switchable(data[6] * data[6] + data[7] * data[7] + data[8] * data[8]))}; data[6] /= z_length; data[7] /= z_length; data[8] /= z_length; @@ -689,41 +738,38 @@ class matrix3 { * Must be called on a symmetrical matrix. * @return Diagonalising quaternion. */ + template [[nodiscard]] inline quaternion constexpr diagonaliser() { // Based loosely on Jacobi Transformations of a Symmetric Matrix, via S Melax. // Adapted from http://melax.github.io/diag.html // Diagonal matrix D = Q * A * Transpose(Q); and A = QT*D*Q // The rows of q are the eigenvectors D's diagonal is the eigenvalues // As per 'row' convention if float3x3 Q = q.getmatrix(); then v*Q = q*v*conj(q) - unsigned int constexpr maxsteps = 24; // certainly wont need that many. + unsigned int constexpr maxsteps{24}; // certainly wont need that many quaternion q(1, 0, 0, 0); - for(unsigned int i = 0; i != maxsteps; ++i) { + for(unsigned int i{0}; i != maxsteps; ++i) { matrix3 const Q{q.rotmatrix()}; // v*Q == q*v*conj(q) matrix3 const D{Q * *this * Q.transpose()}; // A = Q^T*D*Q vector3 offdiag(D.at(1, 2), D.at(0, 2), D.at(0, 1)); // elements not on the diagonal vector3 om(std::fabs(offdiag.x), std::fabs(offdiag.y), std::fabs(offdiag.z)); // mag of each offdiag elem - unsigned int const k = (om.x > om.y && om.x > om.z) ? 0 : (om.y > om.z) ? 1 : 2; // index of largest element of offdiag - unsigned int const k1 = (k + 1) % 3; - unsigned int const k2 = (k + 2) % 3; - if(offdiag[k] == 0.0f) { - break; // diagonal already - } - T thet = (D.at(k2, k2) - D.at(k1, k1)) / (2 * offdiag[k]); - T const sgn = std::signbit(thet) ? -1 : 1; + unsigned int const k{(om.x > om.y && om.x > om.z) ? 0 : (om.y > om.z) ? 1 : 2}; // index of largest element of offdiag + if(offdiag[k] == 0.0f) break; // diagonal already + unsigned int const k1{(k + 1) % 3}; + unsigned int const k2{(k + 2) % 3}; + + T thet{(D.at(k2, k2) - D.at(k1, k1)) / (2 * offdiag[k])}; + T const sgn{std::signbit(thet) ? -1 : 1}; thet *= sgn; // make it positive - T const t = sgn / (thet + ((thet < 1.E6) ? std::sqrt((thet * thet) + 1) : thet)); // sign(T)/(|T|+sqrt(T^2+1)) - T const c = 1 / std::sqrt((t * t) + 1); // c= 1/(t^2+1) , t=s/c - if(c == 1.0f) { - break; - } // no room for improvement - reached machine precision. + T const t{sgn / (thet + ((thet < 1.E6) ? sqrt_switchable((thet * thet) + 1) : thet))}; // sign(T)/(|T|+sqrt(T^2+1)) + T const c{1 / sqrt_switchable((t * t) + 1)}; // c= 1/(t^2+1) , t=s/c + if(c == 1.0f) break; + quaternion jr(0, 0, 0, 0); // jacobi rotation for this iteration. - jr.vector[k] = sgn * std::sqrt((1.0f - c) / 2.0f); // using 1/2 angle identity sin(a/2) = sqrt((1-cos(a))/2) + jr.vector[k] = sgn * sqrt_switchable((1.0f - c) / 2.0f); // using 1/2 angle identity sin(a/2) = sqrt((1-cos(a))/2) jr.vector[k] *= -1.0f; // since our quat-to-matrix convention was for v*M instead of M*v - jr.w = std::sqrt(1.0f - (jr.vector[k] * jr.vector[k])); - if(jr.w == 1.0f) { - break; // reached limits of floating point precision - } - q = q * jr; + jr.w = sqrt_switchable(1.0f - (jr.vector[k] * jr.vector[k])); + if(jr.w == 1.0f) break; // reached limits of floating point precision + q = q * jr; q.normalise(); } return q; @@ -736,6 +782,7 @@ class matrix3 { * @return Pointer to internally stored (in management of class matrix3) * used for passing matrix3 values to gl*[fd]v functions. */ + [[nodiscard]] inline constexpr operator T*() noexcept __attribute__((__always_inline__)) { return reinterpret_cast(data.data()); } @@ -745,6 +792,7 @@ class matrix3 { * @return Constant Pointer to internally stored (in management of class matrix3) * used for passing matrix3 values to gl*[fd]v functions. */ + [[nodiscard]] inline constexpr operator const T*() const noexcept __attribute__((__always_inline__)) { return reinterpret_cast(data.data()); } @@ -757,7 +805,7 @@ class matrix3 { * @return Left hand side argument - the ostream object passed to operator. */ inline friend std::ostream &operator <<(std::ostream &lhs, matrix3 const &rhs) noexcept __attribute__((__always_inline__)) { - for(int i = 0; i != 3; ++i) { + for(unsigned int i{0}; i != 3; ++i) { lhs << "|\t"; for(int j = 0; j != 3; ++j) { lhs << +rhs.at(j, i) << "\t"; @@ -770,6 +818,7 @@ class matrix3 { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -855,7 +904,7 @@ namespace std { * Gets matrix containing minimal values of @a a and @a b coordinates. * @return Matrix of minimal coordinates. */ -template +template [[nodiscard]] inline constexpr matrix3 min(matrix3 const &a, const matrix3 &b) noexcept __attribute__((__always_inline__)) __attribute__ ((pure)); template inline constexpr matrix3 min(matrix3 const &a, const matrix3 &b) noexcept { @@ -876,7 +925,7 @@ inline constexpr matrix3 min(matrix3 const &a, const matrix3 &b) noexce * Gets matrix containing maximal values of @a a and @a b coordinates. * @return Matrix of maximal coordinates. */ -template +template [[nodiscard]] inline constexpr matrix3 max(matrix3 const &a, const matrix3 &b) noexcept __attribute__((__always_inline__)) __attribute__ ((pure)); template inline constexpr matrix3 max(matrix3 const &a, const matrix3 &b) noexcept { diff --git a/vectorstorm/matrix/matrix4.h b/vectorstorm/matrix/matrix4.h index 86bdd8b..055839e 100644 --- a/vectorstorm/matrix/matrix4.h +++ b/vectorstorm/matrix/matrix4.h @@ -191,6 +191,7 @@ class matrix4 { * @param yDeg Angle (in degrees) of rotation around axis Y. * @param zDeg Angle (in degrees) of rotation around axis Z. */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_from_euler_angles(T xDeg, T yDeg, T zDeg) noexcept __attribute__((__always_inline__)) { return create_rotation_from_euler_angles_rad(deg2rad(xDeg), deg2rad(yDeg), deg2rad(zDeg)); } @@ -201,6 +202,7 @@ class matrix4 { * @param yRads Angle (in radians) of rotation around axis Y. * @param zRads Angle (in radians) of rotation around axis Z. */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_from_euler_angles_rad(T xRads, T yRads, T zRads) noexcept __attribute__((__always_inline__)) { return matrix3::create_rotation_from_euler_angles_rad(xRads, yRads, zRads).get_transform(); } @@ -210,6 +212,7 @@ class matrix4 { * @param axis Axis to rotate around. * @param angle Angle (in degrees) of rotation around axis. */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_around_axis(vector3 const &axis, T angle) noexcept __attribute__((__always_inline__)) { return create_rotation_around_axis_rad(axis, deg2rad(angle)); } @@ -219,11 +222,11 @@ class matrix4 { * @param axis Axis to rotate around. * @param angle Angle (in radians) of rotation around axis. */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_around_axis_rad(vector3 const &axis, T angle) noexcept __attribute__((__always_inline__)) { return matrix3::create_rotation_around_axis_rad(axis, angle).get_transform(); } - /// Creates translation matrix /** * Creates translation matrix. * @param x X-direction translation @@ -231,6 +234,7 @@ class matrix4 { * @param z Z-direction translation * @param w for W-coordinate translation (implicitly set to 1) */ + [[nodiscard]] inline static matrix4 constexpr create_translation(T x, T y, T z, T w = 1) noexcept __attribute__((__always_inline__)) { return matrix4(static_cast(1), static_cast(0), static_cast(0), static_cast(0), static_cast(0), static_cast(1), static_cast(0), static_cast(0), @@ -243,6 +247,7 @@ class matrix4 { * * @param v Vector of translation to be set. */ + [[nodiscard]] inline static matrix4 constexpr create_translation(vector3 const &v) noexcept __attribute__((__always_inline__)) { return create_translation(v.x, v.y, v.z); } @@ -252,6 +257,7 @@ class matrix4 { * * @param v Vector of translation to be set. */ + [[nodiscard]] inline static matrix4 constexpr create_translation(vector4 const &v) noexcept __attribute__((__always_inline__)) { return create_translation(v.x, v.y, v.z, v.w); } @@ -264,6 +270,7 @@ class matrix4 { * @param sz Scale in Z-axis * @return Transform matrix 4x4 with scale transformation. */ + [[nodiscard]] inline static matrix4 constexpr create_scale(T sx, T sy, T sz) noexcept __attribute__((__always_inline__)) { return matrix4(sx, static_cast(0), static_cast(0), static_cast(0), static_cast(0), sy, static_cast(0), static_cast(0), @@ -277,6 +284,7 @@ class matrix4 { * @param to Vector to rotate to. * @return An instance of matrix4 representing rotation between the two vectors. */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_between_vectors(vector3 const &from, vector3 const &to) noexcept __attribute__((__always_inline__)) { return matrix3::create_rotation_between_vectors(from, to).get_transform(); } @@ -287,6 +295,7 @@ class matrix4 { * @param up_dir Direction of up vector * @return Resulting matrix that's oriented to the target vector */ + [[nodiscard]] inline static matrix4 constexpr create_rotation_aligned_to_vector(vector3 const &target, vector3 const &up_dir) noexcept __attribute__((__always_inline__)) { return matrix3::create_rotation_aligned_to_vector(target, up_dir).get_transform(); } @@ -298,6 +307,7 @@ class matrix4 { * @param up_dir Direction of up vector * @return Resulting view matrix that's looking at the target point */ + [[nodiscard]] inline static matrix4 constexpr create_look_at(vector3 const &eye_pos, vector3 const &target_pos, vector3 const &up_dir) noexcept __attribute__((__always_inline__)) { vector3 const forward((target_pos - eye_pos).normalise_copy()); vector3 const side(forward.cross(up_dir).normalise_safe_copy()); // Side = forward x up @@ -335,6 +345,7 @@ class matrix4 { * @param far_plane Specify the distance to the far depth clipping plane. Distance must be positive. * @return Projection matrix for specified frustum. */ + [[nodiscard]] inline static matrix4 constexpr create_frustum(T left, T right, T bottom, T top, T near_plane, T far_plane) noexcept __attribute__((__always_inline__)) { /* * 2 near @@ -385,6 +396,7 @@ class matrix4 { * @param far_plane Specify the distance to the farther depth clipping plane. This value is negative if the plane is to be behind the viewer. * @return Othrographic projection matrix. */ + [[nodiscard]] inline static matrix4 constexpr create_ortho(T left, T right, T bottom, T top, T near_plane, T far_plane) noexcept __attribute__((__always_inline__)) { /* 2 * ------------ 0 0 tx @@ -429,7 +441,7 @@ class matrix4 { * @param arr An array of elements for 4x4 matrix in row major order. * @return An instance of matrix4 representing @a arr */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix4 constexpr from_row_major_array(FromT const *arr) noexcept { return matrix4(static_cast(arr[0]), static_cast(arr[4]), static_cast(arr[ 8]), static_cast(arr[12]), static_cast(arr[1]), static_cast(arr[5]), static_cast(arr[ 9]), static_cast(arr[13]), @@ -443,7 +455,7 @@ class matrix4 { * @param arr An array of elements for 4x4 matrix in column major order. * @return An instance of matrix4 representing @a arr */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix4 constexpr from_column_major_array(FromT const *arr) noexcept { return matrix4(static_cast(arr[ 0]), static_cast(arr[ 1]), static_cast(arr[ 2]), static_cast(arr[ 3]), static_cast(arr[ 4]), static_cast(arr[ 5]), static_cast(arr[ 6]), static_cast(arr[ 7]), @@ -457,7 +469,7 @@ class matrix4 { * @param arr An array of elements for 3x4 matrix in row major order. * @return An instance of matrix4 representing @a arr */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static matrix4 constexpr from_row_major_34_array(FromT const *arr) noexcept { return matrix4(static_cast(arr[0]), static_cast(arr[4]), static_cast(arr[ 8]), static_cast(0), static_cast(arr[1]), static_cast(arr[5]), static_cast(arr[ 9]), static_cast(0), @@ -474,6 +486,7 @@ class matrix4 { * | lhs[i] - rhs[i] | < epsilon, * same for y-coordinate, z-coordinate, and w-coordinate. */ + [[nodiscard]] inline bool constexpr operator==(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return std::abs(data[ 0] - rhs.data[ 0]) < epsilon && @@ -520,26 +533,50 @@ class matrix4 { * @param rhs Right hand side argument of binary operator. * @return not (lhs == rhs) :-P */ + [[nodiscard]] inline bool constexpr operator!=(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } //---------------------[ access operators ]--------------------------------- /** - * Get reference to element at postion (x,y). + * Get reference to element at position (x,y). + * @param x Number of column (0..3) + * @param y Number of row (0..3) + */ + [[nodiscard]] + inline T constexpr &operator[](unsigned int x, unsigned int y) noexcept __attribute__((__always_inline__)) { + return data[x * 4 + y]; + } + /** + * Get reference to element at position (x,y). * @param x Number of column (0..3) * @param y Number of row (0..3) */ - inline T constexpr &at(int x, int y) noexcept __attribute__((__always_inline__)) { + [[nodiscard]] + inline T constexpr const &operator[](unsigned int x, unsigned int y) const noexcept __attribute__((__always_inline__)) { return data[x * 4 + y]; } /** - * Get constant reference to element at position (x,y). + * Get reference to element at postion (x,y). Throws an exception if out of range. * @param x Number of column (0..3) * @param y Number of row (0..3) */ - inline T constexpr const &at(int x, int y) const noexcept __attribute__((__always_inline__)) { + [[nodiscard]] + inline T constexpr &at(unsigned int x, unsigned int y) noexcept __attribute__((__always_inline__)) { + if(x > 2 || y > 2) throw std::out_of_range("Matrix access at() function accepts x and y values 0..3, given " + std::to_string(x) + ", " + std::to_string(y)); + return data[x * 4 + y]; + } + + /** + * Get constant reference to element at position (x,y). Throws an exception if out of range. + * @param x Number of column (0..3) + * @param y Number of row (0..3) + */ + [[nodiscard]] + inline T constexpr const &at(unsigned int x, unsigned int y) const noexcept __attribute__((__always_inline__)) { + if(x > 2 || y > 2) throw std::out_of_range("Matrix access at() function accepts x and y values 0..3, given " + std::to_string(x) + ", " + std::to_string(y)); return data[x * 4 + y]; } @@ -548,8 +585,10 @@ class matrix4 { * @param i Number of row (1..4) * @param j Number of column (1..4) */ - inline T constexpr &operator()(int i, int j) noexcept __attribute__((__always_inline__)) { - return data[(j - 1) * 4 + i - 1]; + [[nodiscard]] [[deprecated("Use either multidimensional operator[] or .at(), counting from 0")]] + inline T constexpr &operator()(unsigned int i, unsigned int j) noexcept __attribute__((__always_inline__)) { + assert(j != 0 && j < 5); + return operator[](j - 1, i - 1); } /** @@ -557,8 +596,10 @@ class matrix4 { * @param i Number of row (1..4) * @param j Number of column (1..4) */ - inline T constexpr const &operator()(int i, int j) const noexcept __attribute__((__always_inline__)) { - return data[(j - 1) * 4 + i - 1]; + [[nodiscard]] [[deprecated("Use either multidimensional operator[] or .at(), counting from 0")]] + inline T constexpr const &operator()(unsigned int i, unsigned int j) const noexcept __attribute__((__always_inline__)) { + assert(j != 0 && j < 5); + return operator[](j - 1, i - 1); } /** @@ -576,8 +617,9 @@ class matrix4 { /** * Returns translation part of matrix. */ + [[nodiscard]] inline vector3 constexpr get_translation() const noexcept __attribute__((__always_inline__)) { - return vector3(data[12], data[13], data[14]); + return vector3{data[12], data[13], data[14]}; } /** @@ -600,10 +642,11 @@ class matrix4 { /** * Returns rotation (matrix 3x3) part of matrix. */ + [[nodiscard]] inline matrix3 constexpr get_rotation() const noexcept __attribute__((__always_inline__)) { - return matrix3(data[ 0], data[ 1], data[ 2], + return matrix3{data[ 0], data[ 1], data[ 2], data[ 4], data[ 5], data[ 6], - data[ 8], data[ 9], data[10]); + data[ 8], data[ 9], data[10]}; } /** @@ -621,8 +664,9 @@ class matrix4 { /** * Returns scale part of matrix. */ + [[nodiscard]] inline vector3 constexpr get_scale() const noexcept __attribute__((__always_inline__)) { - return vector3(data[0], data[5], data[10]); + return vector3{data[0], data[5], data[10]}; } /** @@ -713,6 +757,7 @@ class matrix4 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator+(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] + rhs.data[ 0], data[ 1] + rhs.data[ 1], data[ 2] + rhs.data[ 2], data[ 3] + rhs.data[ 3], data[ 4] + rhs.data[ 4], data[ 5] + rhs.data[ 5], data[ 6] + rhs.data[ 6], data[ 7] + rhs.data[ 7], @@ -724,6 +769,7 @@ class matrix4 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator-(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] - rhs.data[ 0], data[ 1] - rhs.data[ 1], data[ 2] - rhs.data[ 2], data[ 3] - rhs.data[ 3], data[ 4] - rhs.data[ 4], data[ 5] - rhs.data[ 5], data[ 6] - rhs.data[ 6], data[ 7] - rhs.data[ 7], @@ -736,6 +782,7 @@ class matrix4 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator+(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] + rhs, data[ 1] + rhs, data[ 2] + rhs, data[ 3] + rhs, data[ 4] + rhs, data[ 5] + rhs, data[ 6] + rhs, data[ 7] + rhs, @@ -747,6 +794,7 @@ class matrix4 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator-(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] - rhs, data[ 1] - rhs, data[ 2] - rhs, data[ 3] - rhs, data[ 4] - rhs, data[ 5] - rhs, data[ 6] - rhs, data[ 7] - rhs, @@ -758,6 +806,7 @@ class matrix4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] * rhs, data[ 1] * rhs, data[ 2] * rhs, data[ 3] * rhs, data[ 4] * rhs, data[ 5] * rhs, data[ 6] * rhs, data[ 7] * rhs, @@ -769,6 +818,7 @@ class matrix4 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(data[ 0] / rhs, data[ 1] / rhs, data[ 2] / rhs, data[ 3] / rhs, data[ 4] / rhs, data[ 5] / rhs, data[ 6] / rhs, data[ 7] / rhs, @@ -817,6 +867,7 @@ class matrix4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator*(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(data[0] * rhs.x + data[4] * rhs.y + data[ 8] * rhs.z + data[12] * rhs.w, data[1] * rhs.x + data[5] * rhs.y + data[ 9] * rhs.z + data[13] * rhs.w, @@ -828,6 +879,7 @@ class matrix4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(data[0] * rhs.x + data[4] * rhs.y + data[ 8] * rhs.z + data[12], data[1] * rhs.x + data[5] * rhs.y + data[ 9] * rhs.z + data[13], @@ -838,6 +890,7 @@ class matrix4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline matrix4 constexpr operator*(matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return matrix4(rhs.data[ 0] * data[ 0] + rhs.data[ 1] * data[ 4] + rhs.data[ 2] * data[ 8] + rhs.data[ 3] * data[12], rhs.data[ 0] * data[ 1] + rhs.data[ 1] * data[ 5] + rhs.data[ 2] * data[ 9] + rhs.data[ 3] * data[13], @@ -876,6 +929,7 @@ class matrix4 { * @return Determinant of matrix * @note This function does 3 * 4 * 6 mul, 3 * 6 add. */ + [[nodiscard]] inline T constexpr det() const noexcept __attribute__((__always_inline__)) { return data[12] * data[9] * data[6] * data[3] - data[8] * data[13] * data[6] * data[3] - data[12] * data[5] * data[10] * data[3] + data[4] * data[13] * data[10] * data[3] @@ -902,6 +956,7 @@ class matrix4 { * @note This is a little bit time consuming operation * (16 * 6 * 3 mul, 16 * 5 add + det() + mul() functions) */ + [[nodiscard("Inverse does not modify the input matrix")]] inline matrix4 constexpr inverse() const noexcept __attribute__((__always_inline__)) { return matrix4(data[9] * data[14] * data[7] - data[13] * data[10] * data[7] + data[13] * data[6] * data[11] - data[5] * data[14] * data[11] - data[9] * data[6] * data[15] + data[5] * data[10] * data[15], @@ -940,6 +995,7 @@ class matrix4 { /** * Transpose matrix. */ + [[nodiscard("Transpose does not modify the input matrix")]] inline matrix4 constexpr transpose() const noexcept __attribute__((__always_inline__)) { return matrix4(data[0], data[4], data[8], data[12], data[1], data[5], data[9], data[13], @@ -956,6 +1012,7 @@ class matrix4 { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input matrix")]] inline matrix4 constexpr lerp(T fact, matrix4 const &rhs) const noexcept __attribute__((__always_inline__)) { return (*this) + (rhs - (*this)) * fact; } @@ -1000,6 +1057,7 @@ class matrix4 { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -1025,7 +1083,7 @@ namespace std { * Gets matrix containing minimal values of @a a and @a b coordinates. * @return Matrix of minimal coordinates. */ -template +template [[nodiscard]] inline constexpr matrix4 min(matrix4 const &a, const matrix4 &b) noexcept __attribute__((__always_inline__)) __attribute__ ((pure)); template inline constexpr matrix4 min(matrix4 const &a, const matrix4 &b) noexcept { @@ -1046,7 +1104,7 @@ inline constexpr matrix4 min(matrix4 const &a, const matrix4 &b) noexce * Gets matrix containing maximal values of @a a and @a b coordinates. * @return Matrix of maximal coordinates. */ -template +template [[nodiscard]] inline constexpr matrix4 max(matrix4 const &a, const matrix4 &b) noexcept __attribute__((__always_inline__)) __attribute__ ((pure)); template inline constexpr matrix4 max(matrix4 const &a, const matrix4 &b) noexcept { diff --git a/vectorstorm/quat/quat.h b/vectorstorm/quat/quat.h index 35efa5e..656b95a 100644 --- a/vectorstorm/quat/quat.h +++ b/vectorstorm/quat/quat.h @@ -50,25 +50,6 @@ class quaternion { vector3 vector; }; - /** - * What square root mode to use, passed as a template parameter to functions like length() - */ - enum class sqrt_mode { - /** - * Use standard library std::sqrt - */ - std, - /** - * Use fast approximation from sqrt_fast.h - */ - fast, - /** - * Use rough version of fast approximation from sqrt_fast.h, with one step instead of two - */ - coarse, - }; - - /** * quaternion constructor, sets quaternion to (0 + 0i + 0j + 0k). */ @@ -135,13 +116,14 @@ class quaternion { /** * Construct quaternion from rotation matrix. */ + template inline constexpr explicit quaternion(matrix3 const &matrix) noexcept __attribute__((__always_inline__)) { // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes // article "quaternion Calculus and Fast Animation". - T const trace = matrix.at(0, 0) + matrix.at(1, 1) + matrix.at(2, 2); + T const trace{matrix.at(0, 0) + matrix.at(1, 1) + matrix.at(2, 2)}; if(trace > 0) { // |w| > 1/2, may as well choose w > 1/2 - T root = std::sqrt(trace + static_cast(1.0)); // 2w + T root{sqrt_switchable(trace + static_cast(1.0))}; // 2w w = static_cast(0.5) * root; root = static_cast(0.5) / root; // 1/(4w) v.x = (matrix.at(2, 1) - matrix.at(1, 2)) * root; @@ -149,20 +131,20 @@ class quaternion { v.z = (matrix.at(1, 0) - matrix.at(0, 1)) * root; } else { // |w| <= 1/2 - unsigned int constexpr next[3] = {1, 2, 0}; + unsigned int constexpr next[3]{1, 2, 0}; - unsigned int i = 0; + unsigned int i{0}; if(matrix.at(1, 1) > matrix.at(0, 0)) { i = 1; } if(matrix.at(2, 2) > matrix.at(i, i)) { i = 2; } - unsigned int j = next[i]; - unsigned int k = next[j]; + unsigned int j{next[i]}; + unsigned int k{next[j]}; - T root = std::sqrt(matrix.at(i, i) - matrix.at(j, j) - matrix.at(k, k) + static_cast(1.0)); - T *q[3] = {&v.x, &v.y, &v.z}; + T root{sqrt_switchable(matrix.at(i, i) - matrix.at(j, j) - matrix.at(k, k) + static_cast(1.0))}; + T *q[3]{&v.x, &v.y, &v.z}; *q[i] = static_cast(0.5) * root; root = static_cast(0.5) / root; w = (matrix.at(k, j) - matrix.at(j, k)) * root; @@ -170,13 +152,14 @@ class quaternion { *q[k] = (matrix.at(k, i) + matrix.at(i, k)) * root; } } + template inline constexpr explicit quaternion(matrix4 const &matrix) noexcept __attribute__((__always_inline__)) { // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes // article "quaternion Calculus and Fast Animation". - T const trace = matrix.at(0, 0) + matrix.at(1, 1) + matrix.at(2, 2); + T const trace{matrix.at(0, 0) + matrix.at(1, 1) + matrix.at(2, 2)}; if(trace > 0) { // |w| > 1/2, may as well choose w > 1/2 - T root = std::sqrt(trace + static_cast(1.0)); // 2w + T root{sqrt_switchable(trace + static_cast(1.0))}; // 2w w = static_cast(0.5) * root; root = static_cast(0.5) / root; // 1/(4w) v.x = (matrix.at(2, 1) - matrix.at(1, 2)) * root; @@ -184,20 +167,20 @@ class quaternion { v.z = (matrix.at(1, 0) - matrix.at(0, 1)) * root; } else { // |w| <= 1/2 - unsigned int constexpr next[3] = {1, 2, 0}; + unsigned int constexpr next[3]{1, 2, 0}; - unsigned int i = 0; + unsigned int i{0}; if(matrix.at(1, 1) > matrix.at(0, 0)) { i = 1; } if(matrix.at(2, 2) > matrix.at(i, i)) { i = 2; } - unsigned int j = next[i]; - unsigned int k = next[j]; + unsigned int j{next[i]}; + unsigned int k{next[j]}; - T root = std::sqrt(matrix.at(i, i) - matrix.at(j, j) - matrix.at(k, k) + static_cast(1.0)); - T *q[3] = {&v.x, &v.y, &v.z}; + T root{sqrt_switchable(matrix.at(i, i) - matrix.at(j, j) - matrix.at(k, k) + static_cast(1.0))}; + T *q[3]{&v.x, &v.y, &v.z}; *q[i] = static_cast(0.5) * root; root = static_cast(0.5) / root; w = (matrix.at(k, j) - matrix.at(j, k)) * root; @@ -265,6 +248,7 @@ class quaternion { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline quaternion constexpr operator+(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return quaternion(w + rhs.w, v + rhs.v); } @@ -273,6 +257,7 @@ class quaternion { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline quaternion constexpr operator*(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return quaternion(w * rhs.w - v.x * rhs.v.x - v.y * rhs.v.y - v.z * rhs.v.z, w * rhs.v.x + v.x * rhs.w + v.y * rhs.v.z - v.z * rhs.v.y, @@ -284,6 +269,7 @@ class quaternion { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline quaternion constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return quaternion(w * rhs, v * rhs); } @@ -292,6 +278,7 @@ class quaternion { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline quaternion constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return quaternion(w / rhs, v / rhs); } @@ -300,6 +287,7 @@ class quaternion { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline quaternion constexpr operator-(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return quaternion(w - rhs.w, v - rhs.v); } @@ -358,10 +346,11 @@ class quaternion { /** * Equality test operator * @param rhs Right hand side argument of binary operator. - * @note Test of equality is based of threshold epsilon value. To be two - * values equal, must satisfy this condition | lhs - rhs | < epsilon, - * for all quaternion coordinates. + * @note Test of equality is based of threshold epsilon value. If VECTORSTORM_SOFT_COMPARE is enabled, + * for two valuesto be considered equal, they must satisfy this condition | lhs - rhs | < epsilon + * for all quaternion coordinates. Otherwise, exact equality comparison is used. */ + [[nodiscard]] inline bool constexpr operator==(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return (std::abs(w - rhs.w) < epsilon) && v == rhs.v; @@ -376,8 +365,9 @@ class quaternion { /** * Inequality test operator * @param rhs Right hand side argument of binary operator. - * @return not (lhs == rhs) :-P + * @return not (lhs == rhs) */ + [[nodiscard]] inline bool constexpr operator!=(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } @@ -385,6 +375,7 @@ class quaternion { * Dot product of two quaternions. * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline T constexpr dot(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return (w * rhs.w) + v.dot(rhs.v); } @@ -394,6 +385,7 @@ class quaternion { * Unary negate operator * @return negated quaternion */ + [[nodiscard]] inline quaternion constexpr operator-() const noexcept __attribute__((__always_inline__)) { return quaternion(-w, -v); } @@ -402,6 +394,7 @@ class quaternion { * Unary conjugate operator * @return conjugated quaternion */ + [[nodiscard]] inline quaternion constexpr operator~() const noexcept __attribute__((__always_inline__)) { return quaternion(w, -v); } @@ -413,6 +406,7 @@ class quaternion { * of length of two quaternion can be used just this value, instead * of more expensive length() method. */ + [[nodiscard]] inline T constexpr length_sq() const noexcept __attribute__((__always_inline__)) { return w * w + v.length_sq(); } @@ -421,23 +415,15 @@ class quaternion { * Get length of quaternion. * @return Length of quaternion. */ - template + template [[nodiscard]] inline T __attribute__((__always_inline__)) constexpr length() const noexcept { - if constexpr(mode == sqrt_mode::std) { - return std::sqrt(length_sq()); - } else if constexpr(mode == sqrt_mode::fast) { - return sqrt_fast(length_sq()); - } else if constexpr(mode == sqrt_mode::coarse) { - return sqrt_coarse(length_sq()); - } else { - static_assert(always_false_v, "Unsupported sqrt_mode"); - } + return sqrt_switchable(length_sq()); } /** * Get length of quaternion, fast approximation. * @return Length of quaternion. */ - [[deprecated("Use length::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::fast>()")]] inline T constexpr length_fast() const noexcept __attribute__((__always_inline__)) { return length(); } @@ -445,7 +431,7 @@ class quaternion { * Get length of quaternion, rougher fast approximation. * @return Length of quaternion. */ - [[deprecated("Use length::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::coarse>()")]] inline T constexpr length_faster() const noexcept __attribute__((__always_inline__)) { return length(); } @@ -465,15 +451,15 @@ class quaternion { inline void constexpr normalise_faster() noexcept __attribute__((__always_inline__)) { normalise(); } - template + template [[nodiscard]] inline quaternion __attribute__((__always_inline__)) constexpr normalise_copy() const noexcept { return *this / length(); } - [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] inline quaternion constexpr normalise_copy_fast() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } - [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] inline quaternion constexpr normalise_copy_faster() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } @@ -482,6 +468,7 @@ class quaternion { v = -v; } + [[nodiscard]] inline quaternion constexpr conjugate_copy() const noexcept __attribute__((__always_inline__)) { return quaternion(w, -v); } @@ -502,6 +489,7 @@ class quaternion { *this /= l; } + [[nodiscard]] inline quaternion constexpr invert_copy() const noexcept __attribute__((__always_inline__)) { return conjugate_copy() / length(); } @@ -513,6 +501,7 @@ class quaternion { * @param z Rotation around z axis (in degrees). * @return quaternion object representing transformation. */ + [[nodiscard]] inline static quaternion constexpr from_euler_angles(T x, T y, T z) noexcept __attribute__((__always_inline__)) { return quaternion(from_axis_rot(vector3(1, 0, 0), x) * from_axis_rot(vector3(0, 1, 0), y) * @@ -526,6 +515,7 @@ class quaternion { * @param z Rotation around z axis (in radians). * @return quaternion object representing transformation. */ + [[nodiscard]] inline static quaternion constexpr from_euler_angles_rad(T x, T y, T z) noexcept __attribute__((__always_inline__)) { return quaternion(from_axis_rot_rad(vector3(1, 0, 0), x) * from_axis_rot_rad(vector3(0, 1, 0), y) * @@ -537,6 +527,7 @@ class quaternion { * @param axis Unit vector expressing axis of rotation. * @param angleDeg Angle of rotation around axis (in degrees). */ + [[nodiscard]] inline static quaternion constexpr from_axis_rot(vector3 const &axis, T angleDeg) noexcept __attribute__((__always_inline__)) { return from_axis_rot_rad(axis, deg2rad(angleDeg)); } @@ -546,6 +537,7 @@ class quaternion { * @param axis Unit vector expressing axis of rotation. * @param angleRad Angle of rotation around axis (in radians). */ + [[nodiscard]] inline static quaternion constexpr from_axis_rot_rad(vector3 const &axis, T angleRad) noexcept __attribute__((__always_inline__)) { T temp_sin = static_cast(0); T temp_cos = static_cast(0); @@ -559,31 +551,32 @@ class quaternion { * @param axis The axis around which the rotation is */ inline void constexpr to_angle_axis(T &angle, vector3 &axis) const noexcept __attribute__((__always_inline__)) { - T const squareLength = v.length_sq(); - if(squareLength != 0) { - angle = static_cast(2) * std::acos(w); - axis = v / std::pow(squareLength, static_cast(0.5)); - } else { + T const square_length{v.length_sq()}; + if(square_length == 0) { angle = static_cast(0); axis.assign(static_cast(1), static_cast(0), static_cast(0)); + return; } + angle = static_cast(2) * std::acos(w); + axis = v / std::pow(square_length, static_cast(0.5)); } /** * Converts quaternion into rotation matrix. * @return Rotation matrix expressing this quaternion. */ + [[nodiscard]] inline matrix3 constexpr rotmatrix() const noexcept __attribute__((__always_inline__)) { return matrix3(static_cast(1) - static_cast(2) * (v.y * v.y + v.z * v.z), - static_cast(2) * (v.x * v.y + v.z * w), - static_cast(2) * (v.x * v.z - v.y * w), + static_cast(2) * (v.x * v.y + v.z * w ), + static_cast(2) * (v.x * v.z - v.y * w ), - static_cast(2) * (v.x * v.y - v.z * w), + static_cast(2) * (v.x * v.y - v.z * w ), static_cast(1) - static_cast(2) * (v.x * v.x + v.z * v.z), - static_cast(2) * (v.y * v.z + v.x * w), + static_cast(2) * (v.y * v.z + v.x * w ), - static_cast(2) * (v.x * v.z + v.y * w), - static_cast(2) * (v.y * v.z - v.x * w), + static_cast(2) * (v.x * v.z + v.y * w ), + static_cast(2) * (v.y * v.z - v.x * w ), static_cast(1) - static_cast(2) * (v.x * v.x + v.y * v.y)); } @@ -593,19 +586,20 @@ class quaternion { * conversion method. But returns matrix of 4x4 elements. * @return Transformation matrix expressing this quaternion. */ + [[nodiscard]] inline matrix4 constexpr transform() const noexcept __attribute__((__always_inline__)) { return matrix4(static_cast(1) - static_cast(2) * (v.y * v.y + v.z * v.z), - static_cast(2) * (v.x * v.y + v.z * w), - static_cast(2) * (v.x * v.z - v.y * w), + static_cast(2) * (v.x * v.y + v.z * w ), + static_cast(2) * (v.x * v.z - v.y * w ), static_cast(0), - static_cast(2) * (v.x * v.y - v.z * w), + static_cast(2) * (v.x * v.y - v.z * w ), static_cast(1) - static_cast(2) * (v.x * v.x + v.z * v.z), - static_cast(2) * (v.y * v.z + v.x * w), + static_cast(2) * (v.y * v.z + v.x * w ), static_cast(0), - static_cast(2) * (v.x * v.z + v.y * w), - static_cast(2) * (v.y * v.z - v.x * w), + static_cast(2) * (v.x * v.z + v.y * w ), + static_cast(2) * (v.y * v.z - v.x * w ), static_cast(1) - static_cast(2) * (v.x * v.x + v.y * v.y), static_cast(0), @@ -624,6 +618,7 @@ class quaternion { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input quaternions")]] inline quaternion constexpr lerp(T fact, quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return quaternion((1 - fact) * w + fact * rhs.w, v.lerp(fact, rhs.v)); } @@ -636,6 +631,7 @@ class quaternion { * @param rhs Second quaternion for interpolation. * @return Result of interpolation. */ + template [[nodiscard("Interpolation does not modify the input quaternions")]] inline quaternion constexpr slerp(T fact, quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { T cos_theta = std::clamp(dot(rhs), static_cast(-1), static_cast(1)); // clamp the dot product, as it can sometimes exceed 1.0 and cause acos to return NaN quaternion rhs_temp(rhs); @@ -647,7 +643,7 @@ class quaternion { if(std::abs(theta) <= epsilon) { return quaternion{*this}; } else { - T const sin_theta = static_cast(std::sqrt(static_cast(1) - cos_theta * cos_theta)); + T const sin_theta = static_cast(sqrt_switchable(static_cast(1) - cos_theta * cos_theta)); //if(std::abs(sin_theta) <= epsilon) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" @@ -675,6 +671,7 @@ class quaternion { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -700,10 +697,11 @@ class quaternion { * @param mat Rotation matrix used to compute quaternion. * @return quaternion representing rotation of matrix m. */ + template [[nodiscard]] inline static quaternion constexpr from_matrix(matrix3 const &mat) noexcept __attribute__((__always_inline__)) { T const tr = mat(1, 1) + mat(2, 2) + mat(3, 3); if(tr >= epsilon) { - T const s = static_cast(0.5) / static_cast(std::sqrt(tr + static_cast(1.0))); + T const s = static_cast(0.5) / static_cast(sqrt_switchable(tr + static_cast(1.0))); return quaternion(static_cast(0.25) / s, (mat(3, 2) - mat(2, 3)) * s, (mat(1, 3) - mat(3, 1)) * s, @@ -711,7 +709,7 @@ class quaternion { } else { if(mat(1, 1) > mat(2, 2)) { if(mat(1, 1) > mat(3, 3)) { - T const s = static_cast(2.0) * static_cast(std::sqrt(static_cast(1.0) + mat(1, 1) - mat(2, 2) - mat(3, 3))); + T const s = static_cast(2.0) * static_cast(sqrt_switchable(static_cast(1.0) + mat(1, 1) - mat(2, 2) - mat(3, 3))); return quaternion((mat(3, 2) - mat(2, 3)) / s, static_cast(0.25) * s, (mat(1, 2) + mat(2, 1)) / s, @@ -719,23 +717,20 @@ class quaternion { } } else { if(mat(2, 2) > mat(3, 3)) { - T const s = static_cast(2.0) * static_cast(std::sqrt(static_cast(1.0) + mat(2, 2) - mat(1, 1) - mat(3, 3))); + T const s = static_cast(2.0) * static_cast(sqrt_switchable(static_cast(1.0) + mat(2, 2) - mat(1, 1) - mat(3, 3))); return quaternion((mat(1, 3) - mat(3, 1)) / s, (mat(1, 2) + mat(2, 1)) / s, static_cast(0.25) * s, (mat(2, 3) + mat(3, 2)) / s); } } - T const s = static_cast(2.0) * static_cast(std::sqrt(static_cast(1.0) + mat(3, 3) - mat(1, 1) - mat(2, 2))); + T const s = static_cast(2.0) * static_cast(sqrt_switchable(static_cast(1.0) + mat(3, 3) - mat(1, 1) - mat(2, 2))); return quaternion((mat(2, 1) - mat(1, 2)) / s, (mat(1, 3) + mat(3, 1)) / s, (mat(2, 3) + mat(3, 2)) / s, static_cast(0.25) * s); } } - -private: - template static constexpr bool always_false_v{false}; }; #ifdef VECTORSTORM_NAMESPACE diff --git a/vectorstorm/sqrt_fast.h b/vectorstorm/sqrt_fast.h index 8a2fceb..0abda97 100644 --- a/vectorstorm/sqrt_fast.h +++ b/vectorstorm/sqrt_fast.h @@ -146,6 +146,42 @@ inline static float sqrt_sse(float number) noexcept { #warning "SSE is not available, performance may be impacted - check your compilation flags." #endif // __SSE__ +/** + * What square root mode to use, passed as a template parameter to functions like length() + */ +enum class sqrt_mode { + /** + * Use standard library std::sqrt + */ + std, + /** + * Use fast approximation from sqrt_fast.h + */ + fast, + /** + * Use rough version of fast approximation from sqrt_fast.h, with one step instead of two + */ + coarse, +}; + +template static constexpr bool sqrt_always_false_v{false}; + +template +inline T constexpr sqrt_switchable(T value) noexcept __attribute__((__always_inline__)); + +template +inline T constexpr sqrt_switchable(T value) noexcept { + if constexpr(mode == sqrt_mode::std) { + return std::sqrt(value); + } else if constexpr(mode == sqrt_mode::fast) { + return sqrt_fast(value); + } else if constexpr(mode == sqrt_mode::coarse) { + return sqrt_coarse(value); + } else { + static_assert(sqrt_always_false_v, "Unsupported sqrt_mode"); + } +}; + #ifdef VECTORSTORM_NAMESPACE } #endif diff --git a/vectorstorm/vector/vector2.h b/vectorstorm/vector/vector2.h index 99b1443..49b2d6e 100644 --- a/vectorstorm/vector/vector2.h +++ b/vectorstorm/vector/vector2.h @@ -67,24 +67,6 @@ class vector2 { T t; }; - /** - * What square root mode to use, passed as a template parameter to functions like length() - */ - enum class sqrt_mode { - /** - * Use standard library std::sqrt - */ - std, - /** - * Use fast approximation from sqrt_fast.h - */ - fast, - /** - * Use rough version of fast approximation from sqrt_fast.h, with one step instead of two - */ - coarse, - }; - //----------------[ constructors ]-------------------------- /** * Creates and sets to (0,0) @@ -259,6 +241,7 @@ class vector2 { * @return For n = 0, reference to x coordinate, else reference to y * y coordinate. */ + [[nodiscard]] inline constexpr T &operator[](unsigned int n) noexcept __attribute__((__always_inline__)) { return n == 0u ? x : y; } @@ -269,6 +252,7 @@ class vector2 { * @return For n = 0, reference to x coordinate, else reference to y * y coordinate. */ + [[nodiscard]] inline constexpr T const &operator[](unsigned int n) const noexcept __attribute__((__always_inline__)) { return n == 0u ? x : y; } @@ -278,6 +262,7 @@ class vector2 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator+(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x + rhs.x, y + rhs.y); } @@ -286,6 +271,7 @@ class vector2 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator-(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x - rhs.x, y - rhs.y); } @@ -294,6 +280,7 @@ class vector2 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator*(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x * rhs.x, y * rhs.y); } @@ -302,6 +289,7 @@ class vector2 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator/(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x / rhs.x, y / rhs.y); } @@ -310,6 +298,7 @@ class vector2 { * Modulo operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator%(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x % rhs.x, y % rhs.y); } @@ -368,6 +357,7 @@ class vector2 { * Dot product of two vectors. * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline T constexpr dot(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x * rhs.x) + (y * rhs.y); @@ -377,6 +367,7 @@ class vector2 { * Cross product of two vectors * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline T constexpr cross(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x * rhs.y) - (y * rhs.x); @@ -387,6 +378,7 @@ class vector2 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator+(T rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x + rhs, y + rhs); } @@ -395,6 +387,7 @@ class vector2 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator-(T rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x - rhs, y - rhs); } @@ -403,6 +396,7 @@ class vector2 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x * rhs, y * rhs); } @@ -411,6 +405,7 @@ class vector2 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x / rhs, y / rhs); } @@ -419,6 +414,7 @@ class vector2 { * Modulo operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector2 constexpr operator%(T rhs) const noexcept __attribute__((__always_inline__)) { return vector2(x % rhs, y % rhs); } @@ -472,6 +468,7 @@ class vector2 { * | lhs.x - rhs.y | < epsilon must be satisfied for each coordinate. * Otherwise, direct equality comparison is used. */ + [[nodiscard]] inline bool constexpr operator==(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return (std::abs(x - rhs.x) < epsilon) && @@ -490,29 +487,17 @@ class vector2 { * @param rhs Right hand side argument of binary operator. * @return not (lhs == rhs) :-P */ + [[nodiscard]] inline bool constexpr operator!=(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } - inline bool constexpr operator==(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { - #ifdef VECTORSTORM_SOFT_COMPARE - return std::abs(x - rhs.x) < epsilon && - std::abs(y - rhs.y) < epsilon && - std::abs(z - rhs.z) < epsilon; - #else - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" - return x == rhs.x && - y == rhs.y && - z == rhs.z; - #pragma GCC diagnostic pop - #endif // VECTORSTORM_SOFT_COMPARE - } /** * Less than test operator * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than rhs' components. */ + [[nodiscard]] inline bool constexpr operator<(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x < rhs.x) && (y < rhs.y); @@ -523,6 +508,7 @@ class vector2 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than rhs' components. */ + [[nodiscard]] inline bool constexpr operator>(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x > rhs.x) && (y > rhs.y); @@ -533,6 +519,7 @@ class vector2 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator<=(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x <= rhs.x) && (y <= rhs.y); @@ -543,6 +530,7 @@ class vector2 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator>=(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x >= rhs.x) && (y >= rhs.y); @@ -553,6 +541,7 @@ class vector2 { * Unary plus operator * @return vector with unary + applied to its components */ + [[nodiscard]] inline vector2 constexpr operator+() const noexcept __attribute__((__always_inline__)) { return vector2(+x, +y); } @@ -560,6 +549,7 @@ class vector2 { * Unary negate operator * @return negated vector */ + [[nodiscard]] inline vector2 constexpr operator-() const noexcept __attribute__((__always_inline__)) { return vector2(-x, -y); } @@ -569,6 +559,7 @@ class vector2 { * Data access * @return pointer to the first element in the vector */ + [[nodiscard]] inline T constexpr *data() noexcept __attribute__((__always_inline__)) { return &x; } @@ -576,6 +567,7 @@ class vector2 { * Data access * @return pointer to the first element in the vector, const version */ + [[nodiscard]] inline T constexpr const *data() const noexcept __attribute__((__always_inline__)) { return &x; } @@ -584,6 +576,7 @@ class vector2 { * Get number of elements in the vector. * @return number of elements (will always return 2) */ + [[nodiscard]] static inline unsigned int constexpr size() noexcept __attribute__((__always_inline__)) __attribute__((__const__)) { return 2u; } @@ -597,6 +590,7 @@ class vector2 { * of length of two vector can be used just this value, instead * of more expensive length() method. */ + [[nodiscard]] inline T constexpr length_sq() const noexcept __attribute__((__always_inline__)) { return x * x + y * y; } @@ -605,23 +599,15 @@ class vector2 { * Get length of vector. * @return length of vector */ - template + template [[nodiscard]] inline T __attribute__((__always_inline__))constexpr length() const noexcept { - if constexpr(mode == sqrt_mode::std) { - return std::sqrt(length_sq()); - } else if constexpr(mode == sqrt_mode::fast) { - return sqrt_fast(length_sq()); - } else if constexpr(mode == sqrt_mode::coarse) { - return sqrt_coarse(length_sq()); - } else { - static_assert(always_false_v, "Unsupported sqrt_mode"); - } + return sqrt_switchable(length_sq()); } /** * Get length of vector, fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::fast>()")]] inline T constexpr length_fast() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -629,7 +615,7 @@ class vector2 { * Get length of vector, rougher fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::coarse>()")]] inline T constexpr length_faster() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -637,12 +623,17 @@ class vector2 { * Return whether the vector is zero length - this is much faster than a full length calculation * @return whether vector is zero length */ + [[nodiscard]] inline bool constexpr length_zero() const noexcept __attribute__((__always_inline__)) { /* - return x == static_cast(0) && - y == static_cast(0); + #ifdef VECTORSTORM_SOFT_COMPARE + ... + #else + return x == static_cast(0) && + y == static_cast(0); + #endif //VECTORSTORM_SOFT_COMPARE */ - // the above may fail to detect cases where the sqrt of three tiny numbers would be zero + // the above may fail to detect cases where the sqrt of two tiny numbers would be zero return std::abs(x) < epsilon && std::abs(y) < epsilon; } @@ -662,15 +653,15 @@ class vector2 { inline void constexpr normalise_faster() noexcept __attribute__((__always_inline__)) { normalise(); } - template + template [[nodiscard]] inline vector2 __attribute__((__always_inline__)) constexpr normalise_copy() const noexcept { return *this / length(); } - [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] inline vector2 constexpr normalise_copy_fast() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } - [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] inline vector2 constexpr normalise_copy_faster() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } @@ -685,7 +676,7 @@ class vector2 { normalise(); } } - template + template [[nodiscard]] inline vector2 __attribute__((__always_inline__)) constexpr normalise_safe_copy() const noexcept { if(length_zero()) { return {}; @@ -701,6 +692,7 @@ class vector2 { x = std::abs(x); y = std::abs(y); } + [[nodiscard]] inline vector2 constexpr abs_copy() const __attribute__((__always_inline__)) { return vector2(std::abs(x), std::abs(y)); } @@ -737,6 +729,7 @@ class vector2 { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input vectors")]] inline vector2 constexpr lerp(T fact, vector2 const &r) const noexcept __attribute__((__always_inline__)) { return (*this) + (r - (*this)) * fact; } @@ -747,6 +740,7 @@ class vector2 { * @return Pointer to internally stored (in management of class vector2) * used for passing vector2 values to gl*2[fd] functions. */ + [[nodiscard]] inline constexpr operator T*() noexcept __attribute__((__always_inline__)) { return reinterpret_cast(this); } @@ -755,6 +749,7 @@ class vector2 { * @return Constant Pointer to internally stored (in management of class vector2) * used for passing vector2 values to gl*2[fd] functions. */ + [[nodiscard]] inline constexpr operator const T*() const noexcept __attribute__((__always_inline__)) { return reinterpret_cast(this); } @@ -774,6 +769,7 @@ class vector2 { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -788,7 +784,7 @@ class vector2 { * @param line2start The start coordinates of the first line * @param line2end The end coordinates of the first line */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline bool constexpr get_line_intersection(vector2 const &line1start, vector2 const &line1end, vector2 const &line2start, @@ -814,7 +810,7 @@ class vector2 { * @param line2start The start coordinates of the first line * @param line2end The end coordinates of the first line */ - template __attribute__((__always_inline__)) + template [[nodiscard]] __attribute__((__always_inline__)) inline static bool constexpr do_lines_intersect(vector2 const &line1start, vector2 const &line1end, vector2 const &line2start, @@ -834,6 +830,7 @@ class vector2 { /** * Gets a 3D vector equivalent populating the X and Y axes */ + [[nodiscard]] inline vector3 constexpr to_3d_xy() const noexcept __attribute__((__always_inline__)) { return vector3(x, y, 0); } @@ -841,11 +838,10 @@ class vector2 { /** * Gets a 3D vector equivalent populating the X and Z axes */ + [[nodiscard]] inline vector3 constexpr to_3d_xz() const noexcept __attribute__((__always_inline__)) { return vector3(x, 0, z); } -private: - template static constexpr bool always_false_v{false}; }; #ifdef VECTORSTORM_NAMESPACE diff --git a/vectorstorm/vector/vector3.h b/vectorstorm/vector/vector3.h index 14a4f9c..e0278b8 100644 --- a/vectorstorm/vector/vector3.h +++ b/vectorstorm/vector/vector3.h @@ -97,24 +97,6 @@ class vector3 { T b; }; - /** - * What square root mode to use, passed as a template parameter to functions like length() - */ - enum class sqrt_mode { - /** - * Use standard library std::sqrt - */ - std, - /** - * Use fast approximation from sqrt_fast.h - */ - fast, - /** - * Use rough version of fast approximation from sqrt_fast.h, with one step instead of two - */ - coarse, - }; - //----------------[ constructors ]-------------------------- /** * Creates and sets to (0,0,0) @@ -359,6 +341,7 @@ class vector3 { * reference to y, else reference to z * y coordinate. */ + [[nodiscard]] inline constexpr T &operator[](unsigned int n) noexcept __attribute__((__always_inline__)) { return n == 0u ? x : (n == 1u ? y : z); } @@ -370,6 +353,7 @@ class vector3 { * reference to y, else reference to z * y coordinate. */ + [[nodiscard]] inline constexpr T const &operator[](unsigned int n) const noexcept __attribute__((__always_inline__)) { return n == 0u ? x : (n == 1u ? y : z); } @@ -379,6 +363,7 @@ class vector3 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator+(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x + rhs.x, y + rhs.y, z + rhs.z); } @@ -387,6 +372,7 @@ class vector3 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator-(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x - rhs.x, y - rhs.y, z - rhs.z); } @@ -395,6 +381,7 @@ class vector3 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x * rhs.x, y * rhs.y, z * rhs.z); } @@ -403,6 +390,7 @@ class vector3 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator/(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x / rhs.x, y / rhs.y, z / rhs.z); } @@ -411,6 +399,7 @@ class vector3 { * Modulo operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator%(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x % rhs.x, y % rhs.y, z % rhs.z); } @@ -473,6 +462,7 @@ class vector3 { * Addition operator with a 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator+(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x + rhs.x, y + rhs.y, z); } @@ -481,6 +471,7 @@ class vector3 { * Subtraction operator with a 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator-(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x - rhs.x, y - rhs.y, z); } @@ -489,6 +480,7 @@ class vector3 { * Multiplication operator with a 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x * rhs.x, y * rhs.y, z); } @@ -497,6 +489,7 @@ class vector3 { * Division operator with a 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator/(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x / rhs.x, y / rhs.y, z); } @@ -505,6 +498,7 @@ class vector3 { * Modulo operator with a 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator%(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x % rhs.x, y % rhs.y, z); } @@ -553,6 +547,7 @@ class vector3 { * Dot product of two vectors. * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline T constexpr dot(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x * rhs.x) + (y * rhs.y) + @@ -563,6 +558,7 @@ class vector3 { * Cross product of two vectors * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr cross(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return {(y * rhs.z) - (rhs.y * z), (z * rhs.x) - (rhs.z * x), @@ -575,6 +571,7 @@ class vector3 { * Multiplication by quaternion operator (rotation by quaternion) * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(quaternion const &rhs) const noexcept __attribute__((__always_inline__)) { return *this + (rhs.v.cross(*this) * static_cast(2) * rhs.w) + rhs.v.cross(rhs.v.cross(*this) * static_cast(2)); } @@ -594,6 +591,7 @@ class vector3 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator+(T rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x + rhs, y + rhs, z + rhs); } @@ -602,6 +600,7 @@ class vector3 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator-(T rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x - rhs, y - rhs, z - rhs); } @@ -610,6 +609,7 @@ class vector3 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x * rhs, y * rhs, z * rhs); } @@ -618,10 +618,20 @@ class vector3 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector3 constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return vector3(x / rhs, y / rhs, z / rhs); } + /** + * Modulo operator + * @param rhs Right hand side argument of binary operator. + */ + [[nodiscard]] + inline vector3 constexpr operator%(T rhs) const noexcept __attribute__((__always_inline__)) { + return vector3(x % rhs, y % rhs, z % rhs); + } + /** * Addition operator * @param rhs Right hand side argument of binary operator. @@ -695,6 +705,7 @@ class vector3 { * | lhs.x - rhs.y | < epsilon must be satisfied for each coordinate. * Otherwise, direct equality comparison is used. */ + [[nodiscard]] inline bool constexpr operator==(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return std::abs(x - rhs.x) < epsilon && @@ -715,6 +726,7 @@ class vector3 { * @param rhs Right hand side argument of binary operator. * @return not (lhs == rhs) :-P */ + [[nodiscard]] inline bool constexpr operator!=(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } @@ -724,6 +736,7 @@ class vector3 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than rhs' components. */ + [[nodiscard]] inline bool constexpr operator<(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x < rhs.x) && (y < rhs.y) && @@ -735,6 +748,7 @@ class vector3 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than rhs' components. */ + [[nodiscard]] inline bool constexpr operator>(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x > rhs.x) && (y > rhs.y) && @@ -746,6 +760,7 @@ class vector3 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator<=(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x <= rhs.x) && (y <= rhs.y) && @@ -757,6 +772,7 @@ class vector3 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator>=(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x >= rhs.x) && (y >= rhs.y) && @@ -768,6 +784,7 @@ class vector3 { * Unary plus operator * @return vector with unary + applied to its components */ + [[nodiscard]] inline vector3 constexpr operator+() const noexcept __attribute__((__always_inline__)) { return vector3(+x, +y, +z); } @@ -775,6 +792,7 @@ class vector3 { * Unary negate operator * @return negated vector */ + [[nodiscard]] inline vector3 constexpr operator-() const noexcept __attribute__((__always_inline__)) { return vector3(-x, -y, -z); } @@ -784,6 +802,7 @@ class vector3 { * Data access * @return pointer to the first element in the vector */ + [[nodiscard]] inline T constexpr *data() noexcept __attribute__((__always_inline__)) { return &x; } @@ -791,6 +810,7 @@ class vector3 { * Data access * @return pointer to the first element in the vector, const version */ + [[nodiscard]] inline T constexpr const *data() const noexcept __attribute__((__always_inline__)) { return &x; } @@ -799,6 +819,7 @@ class vector3 { * Get number of elements in the vector. * @return number of elements (will always return 3) */ + [[nodiscard]] static inline unsigned int constexpr size() noexcept __attribute__((__always_inline__)) __attribute__((__const__)) { return 3u; } @@ -811,6 +832,7 @@ class vector3 { * of length of two vector can be used just this value, instead * of more expensive length() method. */ + [[nodiscard]] inline T constexpr length_sq() const noexcept __attribute__((__always_inline__)) { return x * x + y * y + z * z; } @@ -819,23 +841,15 @@ class vector3 { * Get length of vector. * @return length of vector */ - template + template [[nodiscard]] inline T __attribute__((__always_inline__)) constexpr length() const noexcept { - if constexpr(mode == sqrt_mode::std) { - return std::sqrt(length_sq()); - } else if constexpr(mode == sqrt_mode::fast) { - return sqrt_fast(length_sq()); - } else if constexpr(mode == sqrt_mode::coarse) { - return sqrt_coarse(length_sq()); - } else { - static_assert(always_false_v, "Unsupported sqrt_mode"); - } + return sqrt_switchable(length_sq()); } /** * Get length of vector, fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::fast>()")]] inline T constexpr length_fast() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -843,7 +857,7 @@ class vector3 { * Get length of vector, rougher fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::coarse>()")]] inline T constexpr length_faster() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -851,14 +865,21 @@ class vector3 { * Return whether the vector is zero length - this is much faster than a full length calculation * @return whether vector is zero length */ + [[nodiscard]] inline bool constexpr length_zero() const noexcept __attribute__((__always_inline__)) { /* - return x == static_cast(0) && - y == static_cast(0); + #ifdef VECTORSTORM_SOFT_COMPARE + ... + #else + return x == static_cast(0) && + y == static_cast(0) && + z == static_cast(0); + #endif //VECTORSTORM_SOFT_COMPARE */ // the above may fail to detect cases where the sqrt of three tiny numbers would be zero return std::abs(x) < epsilon && - std::abs(y) < epsilon; + std::abs(y) < epsilon && + std::abs(z) < epsilon; } /** @@ -876,15 +897,15 @@ class vector3 { inline void constexpr normalise_faster() noexcept __attribute__((__always_inline__)) { normalise(); } - template + template [[nodiscard]] inline vector3 __attribute__((__always_inline__)) constexpr normalise_copy() const noexcept { return *this / length(); } - [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] inline vector3 constexpr normalise_copy_fast() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } - [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] inline vector3 constexpr normalise_copy_faster() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } @@ -899,7 +920,7 @@ class vector3 { normalise(); } } - template + template [[nodiscard]] inline vector3 __attribute__((__always_inline__)) constexpr normalise_safe_copy() const noexcept { if(length_zero()) { return {}; @@ -916,6 +937,7 @@ class vector3 { y = std::abs(y); z = std::abs(z); } + [[nodiscard]] inline vector3 constexpr abs_copy() const noexcept __attribute__((__always_inline__)) { return vector3(std::abs(x), std::abs(y), std::abs(z)); } @@ -1030,6 +1052,7 @@ class vector3 { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input vectors")]] inline vector3 constexpr lerp(T fact, vector3 const &new_r) const noexcept __attribute__((__always_inline__)) { return (*this) + (new_r - (*this)) * fact; } @@ -1041,6 +1064,7 @@ class vector3 { * @return Pointer to internally stored (in management of class vector3) * used for passing vector3 values to gl*3[fd] functions. */ + [[nodiscard]] inline constexpr operator T*() noexcept __attribute__((__always_inline__)) { return reinterpret_cast(this); } @@ -1050,6 +1074,7 @@ class vector3 { * @return Constant Pointer to internally stored (in management of class vector3) * used for passing vector3 values to gl*3[fd] functions. */ + [[nodiscard]] inline constexpr operator const T*() const noexcept __attribute__((__always_inline__)) { return reinterpret_cast(this); } @@ -1069,6 +1094,7 @@ class vector3 { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -1078,6 +1104,7 @@ class vector3 { /** * Gets a 2D vector equivalent using the X and Y axes */ + [[nodiscard]] inline vector2 constexpr to_2d_xy() const noexcept __attribute__((__always_inline__)) { return vector2(x, y); } @@ -1085,12 +1112,10 @@ class vector3 { /** * Gets a 2D vector equivalent using the X and Z axes */ + [[nodiscard]] inline vector2 constexpr to_2d_xz() const noexcept __attribute__((__always_inline__)) { return vector2(x, z); } - -private: - template static constexpr bool always_false_v{false}; }; #ifdef VECTORSTORM_NAMESPACE diff --git a/vectorstorm/vector/vector4.h b/vectorstorm/vector/vector4.h index e6ef1b0..008a3a6 100644 --- a/vectorstorm/vector/vector4.h +++ b/vectorstorm/vector/vector4.h @@ -90,24 +90,6 @@ class vector4 { T w; }; - /** - * What square root mode to use, passed as a template parameter to functions like length() - */ - enum class sqrt_mode { - /** - * Use standard library std::sqrt - */ - std, - /** - * Use fast approximation from sqrt_fast.h - */ - fast, - /** - * Use rough version of fast approximation from sqrt_fast.h, with one step instead of two - */ - coarse, - }; - //----------------[ constructors ]-------------------------- /** * Creates and sets to (0,0,0,0) @@ -349,7 +331,6 @@ class vector4 { return *this; } - /** * Move assignment operator * @param rhs Right hand side argument of binary operator. @@ -407,6 +388,7 @@ class vector4 { * reference to y coordinate, n = 2 reference to z, * else reference to w coordinate. */ + [[nodiscard]] inline T constexpr &operator[](unsigned int n) noexcept __attribute__((__always_inline__)) { return n == 0u ? x : (n == 1u ? y : (n == 2u ? z : w)); } @@ -418,6 +400,7 @@ class vector4 { * reference to y coordinate, n = 2 reference to z, * else reference to w coordinate. */ + [[nodiscard]] inline T constexpr const &operator[](unsigned int n) const noexcept __attribute__((__always_inline__)) { return n == 0u ? x : (n == 1u ? y : (n == 2u ? z : w)); } @@ -427,6 +410,7 @@ class vector4 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator+(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w); } @@ -435,6 +419,7 @@ class vector4 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator-(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w); } @@ -443,6 +428,7 @@ class vector4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator*(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x * rhs.x, y * rhs.y, z * rhs.z, w * rhs.w); } @@ -451,6 +437,7 @@ class vector4 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator/(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x / rhs.x, y / rhs.y, z / rhs.z, w / rhs.w); } @@ -507,6 +494,7 @@ class vector4 { * Addition operator with 3-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator+(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x + rhs.x, y + rhs.y, z + rhs.z, w); } @@ -515,6 +503,7 @@ class vector4 { * Subtraction operator with 3-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator-(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x - rhs.x, y - rhs.y, z - rhs.z, w); } @@ -523,6 +512,7 @@ class vector4 { * Multiplication operator with 3-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator*(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x * rhs.x, y * rhs.y, z * rhs.z, w); } @@ -531,6 +521,7 @@ class vector4 { * Division operator with 3-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator/(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x / rhs.x, y / rhs.y, z / rhs.z, w); } @@ -539,6 +530,7 @@ class vector4 { * Modulo operator with 3-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator%(vector3 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x % rhs.x, y % rhs.y, z % rhs.z, w); } @@ -602,6 +594,7 @@ class vector4 { * Addition operator with 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator+(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x + rhs.x, y + rhs.y, z, w); } @@ -610,6 +603,7 @@ class vector4 { * Subtraction operator with 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator-(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x - rhs.x, y - rhs.y, z, w); } @@ -618,6 +612,7 @@ class vector4 { * Multiplication operator with 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator*(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x * rhs.x, y * rhs.y, z, w); } @@ -626,6 +621,7 @@ class vector4 { * Division operator with 2-vector * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator/(vector2 const &rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x / rhs.x, y / rhs.y, z, w); } @@ -711,6 +707,7 @@ class vector4 { * | lhs.x - rhs.y | < epsilon must be satisfied for each coordinate. * Otherwise, direct equality comparison is used. */ + [[nodiscard]] inline bool constexpr operator==(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { #ifdef VECTORSTORM_SOFT_COMPARE return std::abs(x - rhs.x) < epsilon && @@ -733,6 +730,7 @@ class vector4 { * @param rhs Right hand side argument of binary operator. * @return not (lhs == rhs) :-P */ + [[nodiscard]] inline bool constexpr operator!=(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return !(*this == rhs); } @@ -742,6 +740,7 @@ class vector4 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than rhs' components. */ + [[nodiscard]] inline bool constexpr operator<(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x < rhs.x) && (y < rhs.y) && @@ -754,6 +753,7 @@ class vector4 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than rhs' components. */ + [[nodiscard]] inline bool constexpr operator>(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x > rhs.x) && (y > rhs.y) && @@ -766,6 +766,7 @@ class vector4 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are less than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator<=(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x <= rhs.x) && (y <= rhs.y) && @@ -778,6 +779,7 @@ class vector4 { * @param rhs Right hand side argument of binary operator. * @note Returns true if all components are greater than or equal to rhs' components. */ + [[nodiscard]] inline bool constexpr operator>=(vector4 const &rhs) const noexcept __attribute__((__always_inline__)) { return (x >= rhs.x) && (y >= rhs.y) && @@ -790,6 +792,7 @@ class vector4 { * Unary plus operator * @return vector with unary + applied to its components */ + [[nodiscard]] inline vector4 constexpr operator+() const noexcept __attribute__((__always_inline__)) { return vector4(+x, +y, +z, +w); } @@ -797,6 +800,7 @@ class vector4 { * Unary negate operator * @return negated vector */ + [[nodiscard]] inline vector4 constexpr operator-() const noexcept __attribute__((__always_inline__)) { return vector4(-x, -y, -z, -w); } @@ -807,6 +811,7 @@ class vector4 { * Addition operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator+(T rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x + rhs, y + rhs, z + rhs, w + rhs); } @@ -815,6 +820,7 @@ class vector4 { * Subtraction operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator-(T rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x - rhs, y - rhs, z - rhs, w - rhs); } @@ -823,6 +829,7 @@ class vector4 { * Multiplication operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator*(T rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x * rhs, y * rhs, z * rhs, w * rhs); } @@ -831,6 +838,7 @@ class vector4 { * Division operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator/(T rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x / rhs, y / rhs, z / rhs, w / rhs); } @@ -839,6 +847,7 @@ class vector4 { * Modulo operator * @param rhs Right hand side argument of binary operator. */ + [[nodiscard]] inline vector4 constexpr operator%(T rhs) const noexcept __attribute__((__always_inline__)) { return vector4(x % rhs, y % rhs, z % rhs, w % rhs); } @@ -908,6 +917,7 @@ class vector4 { * Data access * @return pointer to the first element in the vector */ + [[nodiscard]] inline T constexpr *data() noexcept __attribute__((__always_inline__)) { return &x; } @@ -915,6 +925,7 @@ class vector4 { * Data access * @return pointer to the first element in the vector, const version */ + [[nodiscard]] inline T constexpr const *data() const noexcept __attribute__((__always_inline__)) { return &x; } @@ -923,6 +934,7 @@ class vector4 { * Get number of elements in the vector. * @return number of elements (will always return 4) */ + [[nodiscard]] static inline unsigned int constexpr size() noexcept __attribute__((__always_inline__)) __attribute__((__const__)) { return 4u; } @@ -935,6 +947,7 @@ class vector4 { * of length of two vector can be used just this value, instead * of more expensive length() method. */ + [[nodiscard]] inline T constexpr length_sq() const noexcept __attribute__((__always_inline__)) { return x * x + y * y + z * z + w * w; } @@ -943,23 +956,15 @@ class vector4 { * Get length of vector. * @return length of vector */ - template + template [[nodiscard]] inline T __attribute__((__always_inline__)) constexpr length() const noexcept { - if constexpr(mode == sqrt_mode::std) { - return std::sqrt(length_sq()); - } else if constexpr(mode == sqrt_mode::fast) { - return sqrt_fast(length_sq()); - } else if constexpr(mode == sqrt_mode::coarse) { - return sqrt_coarse(length_sq()); - } else { - static_assert(always_false_v, "Unsupported sqrt_mode"); - } + return sqrt_switchable(length_sq()); } /** * Get length of vector, fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::fast>()")]] inline T constexpr length_fast() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -967,7 +972,7 @@ class vector4 { * Get length of vector, rougher fast approximation. * @return length of vector */ - [[deprecated("Use length::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use length::sqrt_mode::coarse>()")]] inline T constexpr length_faster() const noexcept __attribute__((__always_inline__)) __attribute__((__pure__)) { return length(); } @@ -975,14 +980,23 @@ class vector4 { * Return whether the vector is zero length - this is much faster than a full length calculation * @return whether vector is zero length */ + [[nodiscard]] inline bool constexpr length_zero() const noexcept __attribute__((__always_inline__)) { /* - return x == static_cast(0) && - y == static_cast(0); + #ifdef VECTORSTORM_SOFT_COMPARE + ... + #else + return x == static_cast(0) && + y == static_cast(0) && + z == static_cast(0) && + w == static_cast(0); + #endif //VECTORSTORM_SOFT_COMPARE */ - // the above may fail to detect cases where the sqrt of three tiny numbers would be zero + // the above may fail to detect cases where the sqrt of four tiny numbers would be zero return std::abs(x) < epsilon && - std::abs(y) < epsilon; + std::abs(y) < epsilon && + std::abs(z) < epsilon && + std::abs(w) < epsilon; } /** @@ -1000,15 +1014,15 @@ class vector4 { inline void constexpr normalise_faster() noexcept __attribute__((__always_inline__)) { normalise(); } - template + template [[nodiscard]] inline vector4 __attribute__((__always_inline__)) constexpr normalise_copy() const noexcept { return *this / length(); } - [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::fast>()")]] inline vector4 constexpr normalise_copy_fast() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } - [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] + [[nodiscard]] [[deprecated("Use normalise_copy::sqrt_mode::coarse>()")]] inline vector4 constexpr normalise_copy_faster() const noexcept __attribute__((__always_inline__)) { return normalise_copy(); } @@ -1023,7 +1037,7 @@ class vector4 { normalise(); } } - template + template [[nodiscard]] inline vector4 __attribute__((__always_inline__)) constexpr normalise_safe_copy() const noexcept { if(length_zero()) { return {}; @@ -1041,6 +1055,7 @@ class vector4 { z = std::abs(z); w = std::abs(w); } + [[nodiscard]] inline vector4 constexpr abs_copy() const noexcept __attribute__((__always_inline__)) { return vector4(std::abs(x), std::abs(y), std::abs(z), std::abs(w)); } @@ -1055,6 +1070,7 @@ class vector4 { * [0.0 , 1.0], you can pass also values outside of this interval and you * can get result (extrapolation?) */ + [[nodiscard("Interpolation does not modify the input vectors")]] inline vector4 constexpr lerp(T fact, vector4 const &new_r) const noexcept __attribute__((__always_inline__)) { return (*this) + (new_r - (*this)) * fact; } @@ -1103,6 +1119,7 @@ class vector4 { /** * Gets string representation. */ + [[nodiscard]] inline std::string CONSTEXPR_IF_NO_CLANG to_string() const noexcept __attribute__((__always_inline__)) { std::ostringstream oss; oss << *this; @@ -1112,12 +1129,10 @@ class vector4 { /** * Gets a 3D vector subset. */ + [[nodiscard]] inline vector3 constexpr to_3d() const noexcept __attribute__((__always_inline__)) { return vector3(x, y, z); } - -private: - template static constexpr bool always_false_v{false}; }; #ifdef VECTORSTORM_NAMESPACE