From 718a10dab4e564a70a258651daf660fecad6e84f Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Sat, 18 Jul 2026 18:05:13 +0300 Subject: [PATCH 01/14] Add missing uint/int/half functions and types --- README.md | 7 +- include/math/color.hpp | 17 +- include/math/common.hpp | 2 + include/math/hex.hpp | 2 +- include/math/matrix/float.hpp | 98 +- include/math/matrix/transform.hpp | 12 +- include/math/normal-mapping.hpp | 10 +- include/math/quaternion.hpp | 10 +- include/math/simd/matrix/float.hpp | 42 +- include/math/simd/types.hpp | 7 +- include/math/simd/vector/float.hpp | 110 +- include/math/simd/vector/half.hpp | 131 ++- include/math/simd/vector/int.hpp | 72 +- include/math/simd/vector/uint.hpp | 70 +- include/math/types.hpp | 24 +- include/math/vector.hpp | 2 +- include/math/vector/byte.hpp | 885 +++++++++++++++ include/math/vector/double.hpp | 1665 ++++++++++++++++++++++++++++ include/math/vector/float.hpp | 331 +++--- include/math/vector/half.hpp | 447 ++++++++ include/math/vector/int.hpp | 223 ++-- include/math/vector/long.hpp | 964 ++++++++++++++++ include/math/vector/sbyte.hpp | 835 ++++++++++++++ include/math/vector/short.hpp | 879 +++++++++++++++ include/math/vector/uint.hpp | 92 +- include/math/vector/ulong.hpp | 878 +++++++++++++++ include/math/vector/ushort.hpp | 896 +++++++++++++++ tests/test-matrix.cpp | 4 +- tests/test-vector.cpp | 4 +- 29 files changed, 8074 insertions(+), 645 deletions(-) create mode 100644 include/math/vector/byte.hpp create mode 100644 include/math/vector/double.hpp create mode 100644 include/math/vector/half.hpp create mode 100644 include/math/vector/long.hpp create mode 100644 include/math/vector/sbyte.hpp create mode 100644 include/math/vector/short.hpp create mode 100644 include/math/vector/ulong.hpp create mode 100644 include/math/vector/ushort.hpp diff --git a/README.md b/README.md index 713336d..aa4aa1b 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,11 @@ See the [documentation](https://cfnptr.github.io/math). ## Features -* Vector (float2/3/4, int2/3/4, half) +* Vector (float2/3/4, int2/3/4, half2/3/4) +* Types (byte, sbyte, short, ushort, int, uint, long, ulong) * Matrix (float2x2/3x3/4x4) -* Quaternion (float4) -* SIMD optimized (f32x4, f32x4x4, f16x4) +* Quaternion rotations (float4) +* SIMD optimized (i32x4, f32x4, f32x4x4, f16x4) * Euler angles/radians conversion * Matrix translate, scale, rotate * Perspective, orthographic projection diff --git a/include/math/color.hpp b/include/math/color.hpp index 2d4ca87..5764108 100644 --- a/include/math/color.hpp +++ b/include/math/color.hpp @@ -60,18 +60,23 @@ struct [[nodiscard]] Color /** * @brief Creates a new sRGB color structure. * - * @param rgb red green and blue channel color value + * @param rgb red, green and blue channel color value * @param a alpha channel color value (transparency) */ constexpr Color(Color rgb, uint8 a) noexcept : r(rgb.r), g(rgb.g), b(rgb.b), a(a) { } /** * @brief Creates a new sRGB color structure. * - * @param rgb red green and blue channel color value + * @param rgb red, green and blue channel color value * @param a alpha channel color value (transparency) */ constexpr Color(Color rgb, float a) noexcept : r(rgb.r), g(rgb.g), b(rgb.b), a(uint8(saturate(a) * 255.0f + 0.5f)) { } + /** + * @brief Creates a new sRGB color structure. + * @param rgba red, green, blue and alpha channel color value + */ + constexpr Color(byte4 rgba) noexcept : r(rgba.x), g(rgba.y), b(rgba.z), a(rgba.w) { } /** * @brief Creates a new sRGB color structure from the binary data. @@ -181,9 +186,13 @@ struct [[nodiscard]] Color */ explicit operator f32x4() const noexcept { return f32x4(r, g, b, a) * (1.0f / 255.0f); } /** - * @brief Returns color binary data. + * @brief Returns color as binary vector. + */ + explicit operator byte4() const noexcept { return *((const byte4*)this); } + /** + * @brief Returns color as unsigned integer value */ - explicit operator uint32() const noexcept { return *(const uint32*)this; } + explicit operator uint32() const noexcept { return *((const uint32*)this); } /******************************************************************************************************************* * @brief Returns sRGB color normalizer R channel. (Red) diff --git a/include/math/common.hpp b/include/math/common.hpp index e184114..fc28ed0 100644 --- a/include/math/common.hpp +++ b/include/math/common.hpp @@ -119,6 +119,8 @@ static float gain(float x, float k) noexcept return (x < 0.5f) ? a : 1.0f - a; } +// TODO: double variants + /** * @brief Returns true if specified value is a power of 2. * diff --git a/include/math/hex.hpp b/include/math/hex.hpp index 601c885..988f4e7 100644 --- a/include/math/hex.hpp +++ b/include/math/hex.hpp @@ -77,7 +77,7 @@ static string toHex8(const uint8* data, psize size) noexcept } /*********************************************************************************************************************** - * @brief Converts hexadecimal string to the 32bit integer value. + * @brief Converts hexadecimal string to the 32-bit integer value. * @param[in] hex target hexadecimal string */ static uint32 toInt32(const string& hex) noexcept { return (uint32)std::stoul(hex, nullptr, 16); } diff --git a/include/math/matrix/float.hpp b/include/math/matrix/float.hpp index 7ef1c93..3c14a03 100644 --- a/include/math/matrix/float.hpp +++ b/include/math/matrix/float.hpp @@ -30,7 +30,7 @@ namespace math { /** - * @brief Floating point 2x2 matrix structure. + * @brief A 2x2 matrix of 32-bit floating-point vectors. * @details Commonly used for basic transformations: translation, scale, rotation, etc. */ struct [[nodiscard]] float2x2 @@ -39,12 +39,12 @@ struct [[nodiscard]] float2x2 float2 c1; /**< Second matrix column. */ /** - * @brief Creates a new floating point 2x2 matrix structure. + * @brief Creates a new 2x2 matrix of 32-bit floating-point vectors. * @param n target value for all columns and rows */ constexpr explicit float2x2(float n = 0.0f) noexcept : c0(n), c1(n) { } /** - * @brief Creates a new floating point 2x2 matrix structure. + * @brief Creates a new 2x2 matrix of 32-bit floating-point vectors. * @details See the @ref float2x2. */ constexpr float2x2( @@ -53,7 +53,7 @@ struct [[nodiscard]] float2x2 c0(float2(c0r0, c0r1)), c1(float2(c1r0, c1r1)) { } /** - * @brief Creates a new floating point 2x2 matrix structure. + * @brief Creates a new 2x2 matrix of 32-bit floating-point vectors. * * @param c0 first matrix column value * @param c1 second matrix column value @@ -136,7 +136,7 @@ inline constexpr float2x2 float2x2::one = float2x2(1.0f); inline constexpr float2x2 float2x2::minusOne = float2x2(-1.0f); /*********************************************************************************************************************** - * @brief Floating point 3x3 matrix structure. + * @brief A 3x3 matrix of 32-bit floating-point vectors. * @details Commonly used for basic transformations: translation, scale, rotation, etc. */ struct [[nodiscard]] float3x3 @@ -146,12 +146,12 @@ struct [[nodiscard]] float3x3 float3 c2; /**< Third matrix column. */ /** - * @brief Creates a new floating point 3x3 matrix structure. + * @brief Creates a new 3x3 matrix of 32-bit floating-point vectors. * @param n target value for all columns and rows */ constexpr explicit float3x3(float n = 0.0f) noexcept : c0(n), c1(n), c2(n) { } /** - * @brief Creates a new floating point 3x3 matrix structure. + * @brief Creates a new 3x3 matrix of 32-bit floating-point vectors. * @details See the @ref float3x3. */ constexpr float3x3( @@ -162,18 +162,13 @@ struct [[nodiscard]] float3x3 c1(float3(c1r0, c1r1, c1r2)), c2(float3(c2r0, c2r1, c2r2)) { } /** - * @brief Creates a new floating point 3x3 matrix structure. + * @brief Creates a new 3x3 matrix of 32-bit floating-point vectors. * * @param c0 first matrix column value * @param c1 second matrix column value * @param c2 third matrix column value */ constexpr float3x3(float3 c0, float3 c1, float3 c2) noexcept : c0(c0), c1(c1), c2(c2) { } - - /** - * @brief Returns matrix 2x2 part. - */ - constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } /** * @brief Returns matrix column by index. @@ -194,6 +189,8 @@ struct [[nodiscard]] float3x3 return ((float3*)this)[i]; } + constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } + constexpr float3x3 operator+(float n) const noexcept { return float3x3(c0 + n, c1 + n, c2 + n); } constexpr float3x3 operator-(float n) const noexcept { return float3x3(c0 - n, c1 - n, c2 - n); } constexpr float3x3 operator*(float n) const noexcept { return float3x3(c0 * n, c1 * n, c2 * n); } @@ -254,7 +251,7 @@ inline constexpr float3x3 float3x3::one = float3x3(1.0f); inline constexpr float3x3 float3x3::minusOne = float3x3(-1.0f); /*********************************************************************************************************************** - * @brief Floating point 4x3 matrix structure. + * @brief A 4x3 matrix of 32-bit floating-point vectors. * @details Commonly used for basic transformations: translation, scale, rotation, etc. */ struct [[nodiscard]] float4x3 @@ -265,12 +262,12 @@ struct [[nodiscard]] float4x3 float3 c3; /**< Fourth matrix column. */ /** - * @brief Creates a new floating point 4x3 matrix structure. + * @brief Creates a new 4x3 matrix of 32-bit floating-point vectors. * @param n target value for all columns and rows */ constexpr explicit float4x3(float n = 0.0f) noexcept : c0(n), c1(n), c2(n), c3(n) { } /** - * @brief Creates a new floating point 4x3 matrix structure. + * @brief Creates a new 4x3 matrix of 32-bit floating-point vectors. * @details See the @ref float3x3. */ constexpr float4x3( @@ -282,7 +279,7 @@ struct [[nodiscard]] float4x3 c2(float3(c2r0, c2r1, c2r2)), c3(float3(c3r0, c3r1, c3r2)) { } /** - * @brief Creates a new floating point 4x3 matrix structure. + * @brief Creates a new 4x3 matrix of 32-bit floating-point vectors. * * @param c0 first matrix column value * @param c1 second matrix column value @@ -291,15 +288,6 @@ struct [[nodiscard]] float4x3 */ constexpr float4x3(float3 c0, float3 c1, float3 c2, float3 c3) noexcept : c0(c0), c1(c1), c2(c2), c3(c3) { } - /** - * @brief Returns matrix 2x2 part. - */ - constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } - /** - * @brief Returns matrix 3x3 part. - */ - constexpr explicit operator float3x3() const noexcept { return float3x3(c0, c1, c2); } - /** * @brief Returns matrix column by index. * @param i target column index @@ -319,6 +307,9 @@ struct [[nodiscard]] float4x3 return ((float3*)this)[i]; } + constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } + constexpr explicit operator float3x3() const noexcept { return float3x3(c0, c1, c2); } + constexpr float4x3 operator+(float n) const noexcept { return float4x3(c0 + n, c1 + n, c2 + n, c3 + n); } constexpr float4x3 operator-(float n) const noexcept { return float4x3(c0 - n, c1 - n, c2 - n, c3 - n); } constexpr float4x3 operator*(float n) const noexcept { return float4x3(c0 * n, c1 * n, c2 * n, c3 * n); } @@ -363,7 +354,7 @@ inline constexpr float4x3 float4x3::one = float4x3(1.0f); inline constexpr float4x3 float4x3::minusOne = float4x3(-1.0f); /*********************************************************************************************************************** - * @brief Floating point 3x4 matrix structure. + * @brief A 3x4 matrix of 32-bit floating-point vectors. * @details Commonly used for basic transformations: translation, scale, rotation, etc. */ struct [[nodiscard]] float3x4 @@ -373,12 +364,12 @@ struct [[nodiscard]] float3x4 float4 c2; /**< Third matrix column. */ /** - * @brief Creates a new floating point 3x4 matrix structure. + * @brief Creates a new 3x4 matrix of 32-bit floating-point vectors. * @param n target value for all columns and rows */ constexpr explicit float3x4(float n = 0.0f) noexcept : c0(n), c1(n), c2(n) { } /** - * @brief Creates a new floating point 3x4 matrix structure. + * @brief Creates a new 3x4 matrix of 32-bit floating-point vectors. * @details See the @ref float3x3. */ constexpr float3x4( @@ -390,7 +381,7 @@ struct [[nodiscard]] float3x4 c1(float4(c1r0, c1r1, c1r2, c1r3)), c2(float4(c2r0, c2r1, c2r2, c2r3)) { } /** - * @brief Creates a new floating point 3x4 matrix structure. + * @brief Creates a new 3x4 matrix of 32-bit floating-point vectors. * * @param c0 first matrix column value * @param c1 second matrix column value @@ -398,15 +389,6 @@ struct [[nodiscard]] float3x4 */ constexpr float3x4(float4 c0, float4 c1, float4 c2) noexcept : c0(c0), c1(c1), c2(c2) { } - /** - * @brief Returns matrix 2x2 part. - */ - constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } - /** - * @brief Returns matrix 3x3 part. - */ - constexpr explicit operator float3x3() const noexcept { return float3x3((float3)c0, (float3)c1, (float3)c2); } - /** * @brief Returns matrix column by index. * @param i target column index @@ -426,6 +408,9 @@ struct [[nodiscard]] float3x4 return ((float4*)this)[i]; } + constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } + constexpr explicit operator float3x3() const noexcept { return float3x3((float3)c0, (float3)c1, (float3)c2); } + constexpr float3x4 operator+(float n) const noexcept { return float3x4(c0 + n, c1 + n, c2 + n); } constexpr float3x4 operator-(float n) const noexcept { return float3x4(c0 - n, c1 - n, c2 - n); } constexpr float3x4 operator*(float n) const noexcept { return float3x4(c0 * n, c1 * n, c2 * n); } @@ -472,7 +457,7 @@ inline constexpr float3x4 float3x4::one = float3x4(1.0f); inline constexpr float3x4 float3x4::minusOne = float3x4(-1.0f); /*********************************************************************************************************************** - * @brief Floating point 4x4 matrix structure. + * @brief A 4x4 matrix of 32-bit floating-point vectors. * @details Commonly used for basic transformations: translation, scale, rotation, etc. */ struct [[nodiscard]] float4x4 @@ -483,12 +468,12 @@ struct [[nodiscard]] float4x4 float4 c3; /**< Fourth matrix column. */ /** - * @brief Creates a new floating point 4x4 matrix structure. + * @brief Creates a new 4x4 matrix of 32-bit floating-point vectors. * @param n target value for all columns and rows */ constexpr explicit float4x4(float n = 0.0f) noexcept : c0(n), c1(n), c2(n), c3(n) { } /** - * @brief Creates a new floating point 4x4 matrix structure. + * @brief Creates a new 4x4 matrix of 32-bit floating-point vectors. * * @param[in] c0 first matrix column value * @param[in] c1 second matrix column value @@ -498,7 +483,7 @@ struct [[nodiscard]] float4x4 constexpr float4x4(float4 c0, float4 c1, float4 c2, float4 c3) noexcept : c0(c0), c1(c1), c2(c2), c3(c3) { } /** - * @brief Creates a new floating point 4x4 matrix structure. + * @brief Creates a new 4x4 matrix of 32-bit floating-point vectors. * @details See the @ref float4x4. */ constexpr float4x4( @@ -511,7 +496,7 @@ struct [[nodiscard]] float4x4 c2(float4(c2r0, c2r1, c2r2, c2r3)), c3(float4(c3r0, c3r1, c3r2, c3r3)) { } /** - * @brief Creates a new floating point 4x4 matrix structure. + * @brief Creates a new 4x4 matrix of 32-bit floating-point vectors. * * @param[in] m4x3 target 4x3 matrix * @param r3 third rows vector @@ -519,7 +504,7 @@ struct [[nodiscard]] float4x4 constexpr float4x4(const float4x3& m4x3, float4 r3 = float4::zero) noexcept : c0(float4(m4x3.c0, r3.x)), c1(float4(m4x3.c1, r3.y)), c2(float4(m4x3.c2, r3.z)), c3(float4(m4x3.c3, r3.w)) { } /** - * @brief Creates a new floating point 4x4 matrix structure. + * @brief Creates a new 4x4 matrix of 32-bit floating-point vectors. * * @param[in] m target 3x3 matrix value * @param c3 third columns SIMD vector @@ -528,22 +513,6 @@ struct [[nodiscard]] float4x4 constexpr float4x4(const float3x3& m, float4 c3 = float4::zero, float4 r3 = float4::zero) noexcept : c0(float4(m.c0, r3.x)), c1(float4(m.c1, r3.y)), c2(float4(m.c2, r3.z)), c3(c3) { } - /** - * @brief Returns matrix 4x3 part. - */ - constexpr explicit operator float4x3() const noexcept - { - return float4x3((float3)c0, (float3)c1, (float3)c2, (float3)c3); - } - /** - * @brief Returns matrix 3x3 part. - */ - constexpr explicit operator float3x3() const noexcept { return float3x3((float3)c0, (float3)c1, (float3)c2); } - /** - * @brief Returns matrix 2x2 part. - */ - constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } - /** * @brief Returns matrix column by index. * @param i target column index @@ -563,6 +532,13 @@ struct [[nodiscard]] float4x4 return ((float4*)this)[i]; } + constexpr explicit operator float4x3() const noexcept + { + return float4x3((float3)c0, (float3)c1, (float3)c2, (float3)c3); + } + constexpr explicit operator float3x3() const noexcept { return float3x3((float3)c0, (float3)c1, (float3)c2); } + constexpr explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } + constexpr float4x4 operator+(float n) const noexcept { return float4x4(c0 + n, c1 + n, c2 + n, c3 + n); } constexpr float4x4 operator-(float n) const noexcept { return float4x4(c0 - n, c1 - n, c2 - n, c3 - n); } constexpr float4x4 operator*(float n) const noexcept { return float4x4(c0 * n, c1 * n, c2 * n, c3 * n); } diff --git a/include/math/matrix/transform.hpp b/include/math/matrix/transform.hpp index c182bb4..f7a1cdc 100644 --- a/include/math/matrix/transform.hpp +++ b/include/math/matrix/transform.hpp @@ -198,7 +198,7 @@ static f32x4x4 extractRotationOnly(const f32x4x4& m) noexcept * @brief Extracts total SIMD matrix rotation quaternion of an object in 3D space. * @param m target rotation SIMD matrix to extract from */ -static quat extractQuat(f32x4x4 m) noexcept +static quat extractQuat(const f32x4x4& m) noexcept { auto c0X = m.c0.getX(), c1Y = m.c1.getY(), c2Z = m.c2.getZ(); auto fourXSquaredMinus1 = c0X - c1Y - c2Z; @@ -265,8 +265,14 @@ static f32x4x4 calcModel(f32x4 position = f32x4::zero, static void extractTransform(const f32x4x4& m, f32x4& position, quat& rotation, f32x4& scale) noexcept { position = getTranslation(m); - rotation = extractQuat(extractRotation(m)); scale = extractScale(m); + + auto r = extractRotationOnly(m); + auto invScale = 1.0f / scale; + r.c0 *= invScale.getX(); + r.c1 *= invScale.getY(); + r.c2 *= invScale.getZ(); + rotation = extractQuat(r); } /** * @brief Extracts total SIMD matrix position and rotation of an object in 3D space. (Decompose) @@ -278,7 +284,7 @@ static void extractTransform(const f32x4x4& m, f32x4& position, quat& rotation, static void extractTransform(const f32x4x4& m, f32x4& position, quat& rotation) noexcept { position = getTranslation(m); - rotation = extractQuat(extractRotationOnly(m)); + rotation = extractQuat(extractRotation(m)); } /*********************************************************************************************************************** diff --git a/include/math/normal-mapping.hpp b/include/math/normal-mapping.hpp index de9cdfd..5bb69dd 100644 --- a/include/math/normal-mapping.hpp +++ b/include/math/normal-mapping.hpp @@ -33,7 +33,7 @@ static float3 unpackNormal(float3 packedNormal) noexcept { return fma(packedNorm static f32x4 packNormal(f32x4 packedNormal) noexcept { return fma(packedNormal, f32x4(0.5f), f32x4(0.5f)); } static f32x4 unpackNormal(f32x4 packedNormal) noexcept { return fma(packedNormal, f32x4(2.0f), f32x4(-1.0f)); } -static f32x4x4 computeTBN(f32x4x4 model, f32x4 normal, f32x4 tangent) noexcept +static f32x4x4 computeTBN(const f32x4x4& model, f32x4 normal, f32x4 tangent) noexcept { assert(normal == normalize3(normal)); assert(tangent == normalize3(tangent)); @@ -63,10 +63,10 @@ static float3x3 fastApproximateTBN(float3 normal) noexcept // Branchless ONB (Du return float3x3(tangent, bitangent, normal); } -static f32x4x4 tbnToTangentSpace(f32x4x4 tbn) noexcept { return transpose3x3(tbn); } -static f32x4 getTbnTangent(f32x4x4 tbn) noexcept { return tbn[0]; } -static f32x4 getTbnBitangent(f32x4x4 tbn) noexcept { return tbn[1]; } -static f32x4 getTbnNormal(f32x4x4 tbn) noexcept { return tbn[2]; } +static f32x4x4 tbnToTangentSpace(const f32x4x4& tbn) noexcept { return transpose3x3(tbn); } +static f32x4 getTbnTangent(const f32x4x4& tbn) noexcept { return tbn[0]; } +static f32x4 getTbnBitangent(const f32x4x4& tbn) noexcept { return tbn[1]; } +static f32x4 getTbnNormal(const f32x4x4& tbn) noexcept { return tbn[2]; } static float3 snapToAxis(float3 normal) noexcept { diff --git a/include/math/quaternion.hpp b/include/math/quaternion.hpp index 5415fb4..b982845 100644 --- a/include/math/quaternion.hpp +++ b/include/math/quaternion.hpp @@ -31,19 +31,19 @@ namespace math { /** - * @brief SIMD 32bit floating point quaternion rotation container. (In 3D space) + * @brief SIMD 32-bit floating point quaternion rotation container. (In 3D space) * @details Represents rotation using complex numbers, avoiding gimbal lock problem. */ -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) quat : public f32x4 +struct [[nodiscard]] quat : public f32x4 { /** - * @brief Creates a new identity SIMD 32bit floating point quaternion structure. + * @brief Creates a new identity SIMD 32-bit floating point quaternion structure. * @note Identity quaternion represents rotation of 0 degrees around all axis. * @param xyzw quaternion parts vector */ quat(f32x4 xyzw = identity) noexcept : f32x4(xyzw) { } /** - * @brief Creates a new SIMD 32bit floating point quaternion structure. + * @brief Creates a new SIMD 32-bit floating point quaternion structure. * * @param x imaginary vector X part * @param y imaginary vector Y part @@ -54,7 +54,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) quat : public f32x4 #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) /** - * @brief Creates a new SIMD 32bit floating point quaternion structure. + * @brief Creates a new SIMD 32-bit floating point quaternion structure. * @param data target vector floating point SIMD data */ quat(_simd_f128 data) : f32x4(data) { } diff --git a/include/math/simd/matrix/float.hpp b/include/math/simd/matrix/float.hpp index 2bd75db..e5bd20d 100644 --- a/include/math/simd/matrix/float.hpp +++ b/include/math/simd/matrix/float.hpp @@ -14,7 +14,7 @@ /*********************************************************************************************************************** * @file - * @brief Common single instruction multiple data (SIMD) floating point vector functions. + * @brief Common single instruction multiple data (SIMD) 32 bit floating point vector functions. */ #pragma once @@ -24,25 +24,25 @@ namespace math { /** - * @brief SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief A 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * @details Commonly used for basic transformations: translation, scale, rotation, etc. * @note Use it when you know how to implement a faster vectorized code. */ -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 +struct [[nodiscard]] f32x4x4 { f32x4 c0, c1, c2, c3; /** - * @brief Creates a new zero initialized SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new zero initialized 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) */ f32x4x4() noexcept = default; /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * @param n target value for all matrix vector components */ explicit f32x4x4(float n) noexcept : c0(n), c1(n), c2(n), c3(n) { } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * @details See the @ref f32x4x4. */ f32x4x4( @@ -55,7 +55,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 c2(f32x4(c2r0, c2r1, c2r2, c2r3)), c3(f32x4(c3r0, c3r1, c3r2, c3r3)) { } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * * @param c0 first matrix column value * @param c1 second matrix column value @@ -64,7 +64,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 */ f32x4x4(f32x4 c0, f32x4 c1, f32x4 c2, f32x4 c3) noexcept : c0(c0), c1(c1), c2(c2), c3(c3) { } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * @warning This constructor duplicates second column vector to the third column! * * @param c0 first matrix column value @@ -74,12 +74,12 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 f32x4x4(f32x4 c0, f32x4 c1, f32x4 c2) noexcept : c0(c0), c1(c1), c2(c2), c3(c2) { } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * @param[in] m target 4x4 matrix value */ explicit f32x4x4(const float4x4& m) noexcept { *this = *((const f32x4x4*)&m); } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * * @param[in] m target 3x3 matrix value * @param r3 third rows SIMD vector @@ -88,7 +88,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 c0(float4(m.c0, r3.getX())), c1(float4(m.c1, r3.getY())), c2(float4(m.c2, r3.getZ())), c3(float4(m.c3, r3.getW())) { } /** - * @brief Creates a new SIMD 32bit floating point 4x4 matrix structure. (float4x4) + * @brief Creates a new 4x4 SIMD matrix of 32-bit floating-point vectors. (float4x4) * * @param[in] m target 3x3 matrix value * @param c3 third columns SIMD vector @@ -116,37 +116,19 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4x4 return ((f32x4*)this)[i]; } - /** - * @brief Returns SIMD matrix as 4x4 floating point matrix. - */ - explicit operator float4x4() const noexcept - { - return *((const float4x4*)this); - } - /** - * @brief Returns SIMD matrix as 4x3 floating point matrix. - */ + explicit operator float4x4() const noexcept { return *((const float4x4*)this); } explicit operator float4x3() const noexcept { return float4x3((float3)c0, (float3)c1, (float3)c2, (float3)c3); } - /** - * @brief Returns SIMD matrix as 3x4 floating point matrix. - */ explicit operator float3x4() const noexcept { return float3x4((float4)c0, (float4)c1, (float4)c2); } - /** - * @brief Returns SIMD matrix as 3x3 floating point matrix. - */ explicit operator float3x3() const noexcept { return float3x3((float3)c0, (float3)c1, (float3)c2); } - /** - * @brief Returns SIMD matrix as 3x3 floating point matrix. - */ explicit operator float2x2() const noexcept { return float2x2((float2)c0, (float2)c1); } /******************************************************************************************************************* diff --git a/include/math/simd/types.hpp b/include/math/simd/types.hpp index dcaa44e..1fb391d 100644 --- a/include/math/simd/types.hpp +++ b/include/math/simd/types.hpp @@ -27,8 +27,6 @@ #include #define MATH_SIMD_SUPPORT_SSE -#define MATH_SIMD_VECTOR_ALIGNMENT 16 - // TODO: AVX512 support when more than 50% devices will be supported on steam hardware survey. #if defined(__AVX2__) @@ -44,10 +42,7 @@ #include #define MATH_SIMD_SUPPORT_NEON -#define MATH_SIMD_VECTOR_ALIGNMENT 16 -#elif defined(__arm__) || defined(_M_ARM) -#define MATH_SIMD_VECTOR_ALIGNMENT 8 #endif #if defined(_MSC_VER) @@ -59,7 +54,7 @@ namespace math #if defined(MATH_SIMD_SUPPORT_SSE) typedef __m128 _simd_f128; -typedef uint64 _simd_f64; +typedef __m128i _simd_f64; typedef __m128i _simd_i128; typedef __m128i _simd_u128; #elif defined(MATH_SIMD_SUPPORT_NEON) diff --git a/include/math/simd/vector/float.hpp b/include/math/simd/vector/float.hpp index efb71f0..eaf9542 100644 --- a/include/math/simd/vector/float.hpp +++ b/include/math/simd/vector/float.hpp @@ -14,12 +14,11 @@ /*********************************************************************************************************************** * @file - * @brief Common single instruction multiple data (SIMD) 32-bit floating point vector functions. + * @brief Common single instruction multiple data (SIMD) 32 bit floating point vector functions. */ #pragma once -#include "math/vector/float.hpp" -#include "math/simd/vector/int.hpp" +#include "math/simd/vector/half.hpp" #if defined(MATH_SIMD_SUPPORT_AVX2) #define MATH_SIMD_FMA(mul1, mul2, add) _mm_fmadd_ps(mul1, mul2, add) // r = mul1 * mul2 + add @@ -32,16 +31,16 @@ namespace math { -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4; +struct [[nodiscard]] f32x4; static u32x4 floatAsUint(f32x4 v) noexcept; static f32x4 uintAsFloat(u32x4 v) noexcept; /** - * @brief SIMD 4 component 32bit floating point vector structure. (float4) + * @brief A 4-component SIMD vector of 32-bit floating-point values. (float4) * @details Commonly used to represent: points, positions, directions, velocities, etc. * @note Use it when you know how to implement a faster vectorized code. */ -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 +struct [[nodiscard]] f32x4 { union { @@ -55,7 +54,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 f32x4& operator=(const f32x4& v) noexcept = default; /** - * @brief Creates a new zero initialized SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new zero initialized 4-component SIMD vector of 32-bit floating-point values. (float4) */ f32x4() noexcept { @@ -68,7 +67,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) * @param xyzw target value for all vector components */ explicit f32x4(float xyzw) noexcept @@ -82,7 +81,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) * * @param x first vector component value * @param y second vector component value @@ -100,7 +99,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) * @warning This constructor duplicates Z component to the W component! * * @param x first vector component value @@ -118,9 +117,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) * - * @param xyz first, second and third vector component values + * @param xyz first, second and third vector component value * @param w fourth vector component value */ f32x4(f32x4 xyz, float w) noexcept @@ -137,17 +136,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 } #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) - /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) - * @param data target vector floating point SIMD data - */ f32x4(_simd_f128 data) noexcept : data(data) { } #endif - /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) - * @param v target vector unsigned integer SIMD data - */ explicit f32x4(u32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -158,10 +149,6 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 floats = v.floats; #endif } - /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) - * @param v target vector signed integer SIMD data - */ explicit f32x4(i32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -172,9 +159,20 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 floats = v.floats; #endif } + explicit f32x4(f16x4 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + data = _mm_cvtph_ps(v.data); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = vcvt_f32_f16(v.data); + #else + floats = (float4)v.halfs; + #endif + } + /******************************************************************************************************************* - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) * @param v target 4 component vector value */ explicit f32x4(float4 v) noexcept @@ -188,7 +186,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) + * @warning This constructor duplicates Z component to the W component! * @param v target 3 component vector value */ explicit f32x4(float3 v) noexcept @@ -202,22 +201,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) - * @param v target 2 component vector value - */ - explicit f32x4(float2 v) noexcept - { - #if defined(MATH_SIMD_SUPPORT_SSE) - data = _mm_set_ps(v.y, v.y, v.y, v.x); - #elif defined(MATH_SIMD_SUPPORT_NEON) - data = (float32x4_t){ v.x, v.y, v.y, v.y }; - #else - floats = float4(v, v.y, v.y); - #endif - } - /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (float4) - * @param[in] v target 4 component vector value pointer (unaligned) + * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) + * @param[in] v target 4 component vector value pointer (UNALIGNED) */ explicit f32x4(const float* v) noexcept { @@ -231,9 +216,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 } /******************************************************************************************************************* - * @brief Loads SIMD 4 component 32bit floating point aligned vector values. + * @brief Loads 4-component SIMD vector of 32-bit floating-point values. * @warning Specified vector pointer must be aligned in the memory!!! - * @param[in] v target 4 component vector value pointer (aligned) + * @param[in] v target 4 component vector value pointer (ALIGNED) */ void loadAligned(const float* v) noexcept { @@ -247,8 +232,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 } /** - * @brief Stores SIMD 4 component 32bit floating point unaligned vector values. - * @param[out] v target 4 component vector value pointer (unaligned) + * @brief Stores 4-component SIMD vector of unaligned 32-bit floating-point values. + * @param[out] v target 4 component vector value pointer (UNALIGNED) */ void store(float* v) noexcept { @@ -261,9 +246,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 #endif } /** - * @brief Stores SIMD 4 component 32bit floating point aligned vector values. + * @brief Stores 4-component SIMD vector of aligned 32-bit floating-point values. * @warning Specified vector pointer must be aligned in the memory!!! - * @param[out] v target 4 component vector value pointer (aligned) + * @param[out] v target 4 component vector value pointer (ALIGNED) */ void storeAligned(float* v) noexcept { @@ -406,9 +391,6 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 */ float operator[](psize i) const noexcept { return floats[i]; } - /** - * @brief Returns as 4 component unsigned integer SIMD vector. - */ explicit operator u32x4() const noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -419,9 +401,6 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 return u32x4((uint4)floats); #endif } - /** - * @brief Returns as 4 component signed integer SIMD vector. - */ explicit operator i32x4() const noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -432,23 +411,20 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) f32x4 return i32x4((uint4)floats); #endif } + explicit operator f16x4() const noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + return vcvt_f16_f32(v.data); + #else + return f16x4((half4)floats); + #endif + } - /** - * @brief Returns SIMD vector as 4 component floating point vector. (xyzw) - */ explicit operator float4() const noexcept { return floats; } - /** - * @brief Returns SIMD vector as 3 component floating point vector. (xyz) - */ explicit operator float3() const noexcept { return (float3)floats; } - /** - * @brief Returns SIMD vector as 2 component floating point vector. (xy) - */ explicit operator float2() const noexcept { return (float2)floats; } - /** - * @brief Returns SIMD first vector component value. (x) - */ - explicit operator float() const noexcept { return getX(); } //****************************************************************************************************************** f32x4 operator+(f32x4 v) const noexcept diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index 429da16..1589b0c 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -14,62 +14,63 @@ /*********************************************************************************************************************** * @file - * @brief Common single instruction multiple data (SIMD) 16-bit floating point vector functions. + * @brief Common single instruction multiple data (SIMD) 16 bit floating point vector functions. */ #pragma once -#include "math/simd/vector/float.hpp" +#include "math/vector/float.hpp" +#include "math/simd/vector/int.hpp" #if defined(MATH_SIMD_SUPPORT_AVX2) || defined(MATH_SIMD_SUPPORT_NEON) || defined(FLT16_MIN) namespace math { /** - * @brief SIMD 4 component 16bit floating point vector structure. (half4) + * @brief A 4-component SIMD vector of 16-bit floating-point values. (half4) * @note Use it when you know how to implement a faster vectorized code. */ -struct [[nodiscard]] alignas(8) f16x4 +struct [[nodiscard]] f16x4 { union { _simd_f64 data; - half floats[4]; - int16 ints[4]; - uint16 uints[4]; + half4 halfs; + short4 shorts; + ushort4 ushorts; }; f16x4(const f16x4& v) noexcept = default; f16x4& operator=(const f16x4& v) noexcept = default; /** - * @brief Creates a new zero initialized SIMD 4 component 16bit floating point vector structure. (half4) + * @brief Creates a new zero initialized 4-component SIMD vector of 16-bit floating-point values. (half4) */ f16x4() noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = 0; + data = _mm_setzero_si128(); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vdup_n_f16(0.0f); #else - memset(floats, 0, sizeof(half) * 4); + halfs = half4::zero; #endif } /** - * @brief Creates a new SIMD 4 component 16bit floating point vector structure. (half4) + * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) * @param xyzw target value for all vector components */ explicit f16x4(half xyzw) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - _mm_storel_epi64((__m128i*)&data, _mm_cvtps_ph(_mm_set1_ps(xyzw), _MM_FROUND_TO_NEAREST_INT)); + data = _mm_cvtps_ph(_mm_set1_ps(xyzw), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vdup_n_f16(xyzw); #else - floats[0] = xyzw; floats[1] = xyzw; floats[2] = xyzw; floats[3] = xyzw; + halfs = half4(xyzw); #endif } /** - * @brief Creates a new SIMD 4 component 16bit floating point vector structure. (half4) + * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) * * @param x first vector component value * @param y second vector component value @@ -79,15 +80,15 @@ struct [[nodiscard]] alignas(8) f16x4 f16x4(half x, half y, half z, half w) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - _mm_storel_epi64((__m128i*)&data, _mm_cvtps_ph(_mm_set_ps(w, z, y, x), _MM_FROUND_TO_NEAREST_INT)); + data = _mm_cvtps_ph(_mm_set_ps(w, z, y, x), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ x, y, z, w }; #else - floats[0] = x; floats[1] = y; floats[2] = z; floats[3] = w; + halfs = half4(x, y, z, w); #endif } /** - * @brief Creates a new SIMD 4 component 16bit floating point vector structure. (half4) + * @brief Creates a new SIMD 4-component SIMD vector of 16-bit floating-point values. (half4) * @warning This constructor duplicates Z component to the W component! * * @param x first vector component value @@ -97,109 +98,119 @@ struct [[nodiscard]] alignas(8) f16x4 f16x4(half x, half y, half z) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - _mm_storel_epi64((__m128i*)&data, _mm_cvtps_ph(_mm_set_ps(z, z, y, x), _MM_FROUND_TO_NEAREST_INT)); + data = _mm_cvtps_ph(_mm_set_ps(z, z, y, x), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ x, y, z, z }; #else - floats[0] = x; floats[1] = y; floats[2] = z; floats[3] = z; + halfs = half4(x, y, z, z); #endif } - - #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) - /** - * @brief Creates a new SIMD 4 component 16bit floating point vector structure. (half4) - * @param data target vector floating point SIMD data - */ - f16x4(_simd_f64 data) noexcept : data(data) { } - #endif - /** - * @brief Creates a new SIMD 4 component 16bit floating point vector structure. (half4) - * @param v target vector unsigned integer SIMD data + * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value */ - explicit f16x4(f32x4 v) noexcept + f16x4(f16x4 xyz, half w) noexcept { - #if defined(MATH_SIMD_SUPPORT_AVX2) - _mm_storel_epi64((__m128i*)&data, _mm_cvtps_ph(v.data, _MM_FROUND_TO_NEAREST_INT)); + #if defined(MATH_SIMD_SUPPORT_SSE4_1) + data = _mm_blend_epi16(xyz.data, _mm_set1_epi16(*(short*)&w), 8); + #elif defined(MATH_SIMD_SUPPORT_SSE) + data = _mm_insert_epi16(xyz.data, *(uint16*)&w, 3); #elif defined(MATH_SIMD_SUPPORT_NEON) - data = vcvt_f16_f32(v.data); + data = vset_lane_f16(w, xyz.data, 3); #else - floats[0] = (half)v.floats[0]; floats[1] = (half)v.floats[1]; - floats[2] = (half)v.floats[2]; floats[3] = (half)v.floats[3]; + halfs = xyz.halfs; halfs.w = w; #endif } + #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) + f16x4(_simd_f64 data) noexcept : data(data) { } + #endif + /******************************************************************************************************************* * @brief Returns SIMD vector first component value. */ - half getX() const noexcept { return floats[0]; } + half getX() const noexcept { return halfs[0]; } /** * @brief Returns SIMD vector second component value. */ - half getY() const noexcept { return floats[1]; } + half getY() const noexcept { return halfs[1]; } /** * @brief Returns SIMD vector third component value. */ - half getZ() const noexcept { return floats[2]; } + half getZ() const noexcept { return halfs[2]; } /** * @brief Returns SIMD vector fourth component value. */ - half getW() const noexcept { return floats[3]; } + half getW() const noexcept { return halfs[3]; } /** * @brief Sets SIMD vector first component value. * @param value target X vector component value */ - void setX(half value) noexcept { floats[0] = value; } + void setX(half value) noexcept { halfs[0] = value; } /** * @brief Sets SIMD vector second component value. * @param value target Y vector component value */ - void setY(half value) noexcept { floats[1] = value; } + void setY(half value) noexcept { halfs[1] = value; } /** * @brief Sets SIMD vector third component value. * @param value target Z vector component value */ - void setZ(half value) noexcept { floats[2] = value; } + void setZ(half value) noexcept { halfs[2] = value; } /** * @brief Sets SIMD vector fourth component value. * @param value target W vector component value */ - void setW(half value) noexcept { floats[3] = value; } + void setW(half value) noexcept { halfs[3] = value; } /** * @brief Sets SIMD vector Z component value to the W component. * @note Useful when you want to prevent SIMD division by zero. */ - void fixW() noexcept { floats[3] = getZ(); } + void fixW() noexcept { halfs[3] = getZ(); } /******************************************************************************************************************* * @brief Returns SIMD vector component by index. * @param i target component index */ - half& operator[](psize i) noexcept { return floats[i]; } + half& operator[](psize i) noexcept { return halfs[i]; } /** * @brief Returns SIMD vector component by index. * @param i target component index */ - half operator[](psize i) const noexcept { return floats[i]; } + half operator[](psize i) const noexcept { return halfs[i]; } - /** - * @brief Returns as 4 component unsigned integer SIMD vector. - */ - explicit operator f32x4() const noexcept - { - #if defined(MATH_SIMD_SUPPORT_AVX2) - return _mm_cvtph_ps(_mm_loadl_epi64((__m128i*)&data)); - #elif defined(MATH_SIMD_SUPPORT_NEON) - return vcvt_f32_f16(data); - #else - return f32x4(floats[0], floats[1], floats[2], floats[3]); - #endif - } + explicit operator half4() const noexcept { return halfs; } + explicit operator half3() const noexcept { return (half3)halfs; } + explicit operator half2() const noexcept { return (half2)halfs; } // TODO: math functions after adding AVX512 support. + + static const f16x4 zero, one, minusOne, min, minusMin, max, minusMax, + epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; }; +//********************************************************************************************************************** +inline const f16x4 f16x4::zero = f16x4(0.0f); +inline const f16x4 f16x4::one = f16x4(1.0f); +inline const f16x4 f16x4::minusOne = f16x4(-1.0f); +inline const f16x4 f16x4::min = f16x4(FLT16_MIN); +inline const f16x4 f16x4::minusMin = f16x4(-FLT16_MIN); +inline const f16x4 f16x4::max = f16x4(FLT16_MAX); +inline const f16x4 f16x4::minusMax = f16x4(-FLT16_MAX); +inline const f16x4 f16x4::epsilon = f16x4(FLT16_EPSILON); +inline const f16x4 f16x4::inf = f16x4(INFINITY); +inline const f16x4 f16x4::minusInf = f16x4(-INFINITY); +inline const f16x4 f16x4::nan = f16x4(NAN); +inline const f16x4 f16x4::left = f16x4(-1.0f, 0.0f, 0.0f, 0.0f); +inline const f16x4 f16x4::right = f16x4(1.0f, 0.0f, 0.0f, 0.0f); +inline const f16x4 f16x4::bottom = f16x4(0.0f, -1.0f, 0.0f, 0.0f); +inline const f16x4 f16x4::top = f16x4(0.0f, 1.0f, 0.0f, 0.0f); +inline const f16x4 f16x4::back = f16x4(0.0f, 0.0f, -1.0f, 0.0f); +inline const f16x4 f16x4::front = f16x4(0.0f, 0.0f, 1.0f, 0.0f); + } // namespace math #endif \ No newline at end of file diff --git a/include/math/simd/vector/int.hpp b/include/math/simd/vector/int.hpp index d2186da..5c3081d 100644 --- a/include/math/simd/vector/int.hpp +++ b/include/math/simd/vector/int.hpp @@ -14,21 +14,20 @@ /*********************************************************************************************************************** * @file - * @brief Common single instruction multiple data (SIMD) 32-bit signed integer vector functions. + * @brief Common single instruction multiple data (SIMD) 32 bit signed integer vector functions. */ #pragma once -#include "math/vector/int.hpp" #include "math/simd/vector/uint.hpp" namespace math { /** - * @brief SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief A 4-component SIMD vector of 32-bit signed integer values. (int4) * @note Use it when you know how to implement a faster vectorized code. */ -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 +struct [[nodiscard]] i32x4 { union { @@ -42,7 +41,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 i32x4& operator=(const i32x4& v) noexcept = default; /** - * @brief Creates a new zero initialized SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new zero initialized 4-component SIMD vector of 32-bit signed integer values. (int4) */ i32x4() noexcept { @@ -55,7 +54,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @param xyzw target value for all vector components */ explicit i32x4(int32 xyzw) noexcept @@ -69,7 +68,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * * @param x first vector component value * @param y second vector component value @@ -87,7 +86,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @warning This constructor duplicates Z component to the W component! * * @param x first vector component value @@ -105,9 +104,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * - * @param xyz first, second and third vector component values + * @param xyz first, second and third vector component value * @param w fourth vector component value */ i32x4(i32x4 xyz, int32 w) noexcept @@ -125,14 +124,14 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @param data target vector SIMD data */ i32x4(_simd_i128 data) noexcept : data(data) { } #endif /** - * @brief Creates a new SIMD 4 component 32bit floating point vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @param v target vector unsigned integer SIMD data */ explicit i32x4(u32x4 v) noexcept @@ -147,7 +146,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 } /******************************************************************************************************************* - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @param v target 4 component vector value */ explicit i32x4(int4 v) noexcept @@ -161,7 +160,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) + * @warning This constructor duplicates Z component to the W component! * @param v target 3 component vector value */ explicit i32x4(int3 v) noexcept @@ -175,21 +175,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit signed integer vector structure. (int4) - * @param v target 2 component vector value - */ - explicit i32x4(int2 v) noexcept - { - #if defined(MATH_SIMD_SUPPORT_SSE) - data = _mm_set_epi32(v.y, v.y, v.y, v.x); - #elif defined(MATH_SIMD_SUPPORT_NEON) - data = (int32x4_t){ v.x, v.y, v.y, v.y }; - #else - ints = int4(v, v.y, v.y); - #endif - } - /** - * @brief Creates a new SIMD 4 component vector 32bit signed integer structure. (int4) + * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) * @param[in] v target 4 component vector value pointer (unaligned) */ explicit i32x4(const int32* v) noexcept @@ -204,9 +190,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 } /******************************************************************************************************************* - * @brief Loads SIMD 4 component 32bit signed integer aligned vector values. + * @brief Loads 4-component SIMD vector of aligned 32-bit signed integer values. (int4) * @warning Specified vector pointer must be aligned in the memory!!! - * @param[in] v target 4 component vector value pointer (aligned) + * @param[in] v target 4 component vector value pointer (ALIGNED) */ void loadAligned(const int32* v) noexcept { @@ -220,8 +206,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 } /** - * @brief Stores SIMD 4 component 32bit signed integer unaligned vector values. - * @param[out] v target 4 component vector value pointer (unaligned) + * @brief Stores 4-component SIMD vector of unaligned 32-bit signed integer values. (int4) + * @param[out] v target 4 component vector value pointer (UNALIGNED) */ void store(int32* v) noexcept { @@ -234,9 +220,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } /** - * @brief Stores SIMD 4 component 32bit signed integer aligned vector values. + * @brief Stores 4-component SIMD vector of aligned 32-bit signed integer values. (int4) * @warning Specified vector pointer must be aligned in the memory!!! - * @param[out] v target 4 component vector value pointer (aligned) + * @param[out] v target 4 component vector value pointer (ALIGNED) */ void storeAligned(int32* v) noexcept { @@ -364,9 +350,6 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 */ int32 operator[](psize i) const noexcept { return ints[i]; } - /** - * @brief Returns as 4 component unsigned integer SIMD vector. - */ explicit operator u32x4() const noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -378,22 +361,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) i32x4 #endif } - /** - * @brief Returns SIMD vector as 4 component signed integer vector. (xyzw) - */ explicit operator int4() const noexcept { return ints; } - /** - * @brief Returns SIMD vector as 3 component signed integer vector. (xyz) - */ explicit operator int3() const noexcept { return (int3)ints; } - /** - * @brief Returns SIMD vector as 2 component signed integer vector. (xy) - */ explicit operator int2() const noexcept { return (int2)ints; } - /** - * @brief Returns SIMD first vector component value. (x) - */ - explicit operator int32() const noexcept { return getX(); } //****************************************************************************************************************** i32x4 operator+(i32x4 v) const noexcept diff --git a/include/math/simd/vector/uint.hpp b/include/math/simd/vector/uint.hpp index 30f9ea0..64f8702 100644 --- a/include/math/simd/vector/uint.hpp +++ b/include/math/simd/vector/uint.hpp @@ -14,12 +14,12 @@ /*********************************************************************************************************************** * @file - * @brief Common single instruction multiple data (SIMD) 32-bit unsigned integer vector functions. + * @brief Common single instruction multiple data (SIMD) 32 bit unsigned integer vector functions. */ #pragma once #include "math/simd/types.hpp" -#include "math/vector/uint.hpp" +#include "math/vector/float.hpp" namespace math { @@ -31,10 +31,10 @@ static constexpr uint32 SwW = 3; /**< SIMD vector swizzle W component index. */ static constexpr uint32 SwU = 2; /**< SIMD vector swizzle unused component index. */ /** - * @brief SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief A 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * @note Use it when you know how to implement a faster vectorized code. */ -struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 +struct [[nodiscard]] u32x4 { union { @@ -48,7 +48,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 u32x4& operator=(const u32x4& v) noexcept = default; /** - * @brief Creates a new zero initialized SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new zero initialized 4-component SIMD vector of 32-bit unsigned integer values. (uint4) */ u32x4() noexcept { @@ -61,7 +61,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * @param xyzw target value for all vector components */ explicit u32x4(uint32 xyzw) noexcept @@ -75,7 +75,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * * @param x first vector component value * @param y second vector component value @@ -93,7 +93,7 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * @warning This constructor duplicates Z component to the W component! * * @param x first vector component value @@ -111,9 +111,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * - * @param xyz first, second and third vector component values + * @param xyz first, second and third vector component value * @param w fourth vector component value */ u32x4(u32x4 xyz, uint32 w) noexcept @@ -131,14 +131,14 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * @param data target vector SIMD data */ u32x4(_simd_u128 data) noexcept : data(data) { } #endif /******************************************************************************************************************* - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) * @param v target 4 component vector value */ explicit u32x4(uint4 v) noexcept @@ -152,7 +152,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) + * @warning This constructor duplicates Z component to the W component! * @param v target 3 component vector value */ explicit u32x4(uint3 v) noexcept @@ -166,22 +167,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Creates a new SIMD 4 component 32bit unsigned integer vector structure. (uint4) - * @param v target 2 component vector value - */ - explicit u32x4(uint2 v) noexcept - { - #if defined(MATH_SIMD_SUPPORT_SSE) - data = _mm_set_epi32((int)v.y, (int)v.y, (int)v.y, (int)v.x); - #elif defined(MATH_SIMD_SUPPORT_NEON) - data = (uint32x4_t){ v.x, v.y, v.y, v.y }; - #else - uints = uint4(v, v.y, v.y); - #endif - } - /** - * @brief Creates a new SIMD 4 component vector 32bit unsigned integer structure. (uint4) - * @param[in] v target 4 component vector value pointer (unaligned) + * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) + * @param[in] v target 4 component vector value pointer (UNALIGNED) */ explicit u32x4(const uint32* v) noexcept { @@ -195,9 +182,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 } /******************************************************************************************************************* - * @brief Loads SIMD 4 component 32bit unsigned integer aligned vector value. + * @brief Loads 4-component SIMD vector of aligned 32-bit unsigned integer values. (uint4) * @warning Specified vector pointer must be aligned in the memory!!! - * @param[in] v target 4 component vector value pointer (aligned) + * @param[in] v target 4 component vector value pointer (ALIGNED) */ void loadAligned(const uint32* v) noexcept { @@ -211,8 +198,8 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 } /** - * @brief Stores SIMD 4 component 32bit unsigned integer unaligned vector value. - * @param[out] v target 4 component vector value pointer (unaligned) + * @brief Stores 4-component SIMD vector of unaligned 32-bit unsigned integer values. (uint4) + * @param[out] v target 4 component vector value pointer (UNALIGNED) */ void store(uint32* v) noexcept { @@ -225,9 +212,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 #endif } /** - * @brief Stores SIMD 4 component 32bit unsigned integer aligned vector value. + * @brief Stores 4-component SIMD vector of aligned 32-bit unsigned integer values. (uint4) * @warning Specified vector pointer must be aligned in the memory!!! - * @param[out] v target 4 component vector value pointer (aligned) + * @param[out] v target 4 component vector value pointer (ALIGNED) */ void storeAligned(uint32* v) noexcept { @@ -355,22 +342,9 @@ struct [[nodiscard]] alignas(MATH_SIMD_VECTOR_ALIGNMENT) u32x4 */ uint32 operator[](psize i) const noexcept { return uints[i]; } - /** - * @brief Returns SIMD vector as 4 component unsigned integer vector. (xyzw) - */ explicit operator uint4() const noexcept { return uints; } - /** - * @brief Returns SIMD vector as 3 component unsigned integer vector. (xyz) - */ explicit operator uint3() const noexcept { return (uint3)uints; } - /** - * @brief Returns SIMD vector as 2 component unsigned integer vector. (xy) - */ explicit operator uint2() const noexcept { return (uint2)uints; } - /** - * @brief Returns SIMD first vector component value. (x) - */ - explicit operator uint32() const noexcept { return getX(); } //****************************************************************************************************************** u32x4 operator+(u32x4 v) const noexcept diff --git a/include/math/types.hpp b/include/math/types.hpp index 22f8b97..a54a17d 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -28,53 +28,53 @@ #define _Float16 uint16_t // Note: MSVC fix #endif -#define FLOAT_SMALL_16 0.00006103515625f -#define FLOAT_BIG_16 65504.0f +#define FLOAT_SMALL_16 0.00006103515625f /**< Maximum representable finite positive 16-bit value. */ +#define FLOAT_BIG_16 65504.0f /**< Smallest positive normalized 16-bit value. */ namespace math { /** - * @brief Signed 8bit integer type. (-128 to 127) + * @brief A signed 8-bit integer type. (-128 to 127) */ typedef int8_t int8; /** - * @brief Signed 16bit integer type. (-32,768 to 32,767) + * @brief A signed 16-bit integer type. (-32,768 to 32,767) */ typedef int16_t int16; /** - * @brief Signed 32bit integer type. (-2,147,483,648 to 2,147,483,647) + * @brief A signed 32-bit integer type. (-2,147,483,648 to 2,147,483,647) */ typedef int32_t int32; /** - * @brief Signed 64bit integer type. (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) + * @brief A signed 64-bit integer type. (-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807) */ typedef int64_t int64; /** - * @brief Unsigned 8bit integer type. (0 to 255) + * @brief An unsigned 8-bit integer type. (0 to 255) */ typedef uint8_t uint8; /** - * @brief Unsigned 16bit integer type. (0 to 65,535) + * @brief An unsigned 16-bit integer type. (0 to 65,535) */ typedef uint16_t uint16; /** - * @brief Unsigned 32bit integer type. (0 to 4,294,967,295) + * @brief An unsigned 32-bit integer type. (0 to 4,294,967,295) */ typedef uint32_t uint32; /** - * @brief Unsigned 64bit integer type. (0 to 18,446,744,073,709,551,615) + * @brief An unsigned 64-bit type. (0 to 18,446,744,073,709,551,615) */ typedef uint64_t uint64; /** - * @brief Unsigned pointer type. (CPU architecture dependant) + * @brief Unsigned pointer type. (CPU architecture dependant!) */ typedef size_t psize; /** - * @brief Signed 16bit floating point type. (Half precision float) + * @brief An IEEE-754 half-precision 16-bit floating point number. */ typedef _Float16 half; diff --git a/include/math/vector.hpp b/include/math/vector.hpp index 63e09af..15b53d6 100644 --- a/include/math/vector.hpp +++ b/include/math/vector.hpp @@ -23,4 +23,4 @@ */ #pragma once -#include "math/simd/vector/half.hpp" \ No newline at end of file +#include "math/simd/vector/float.hpp" \ No newline at end of file diff --git a/include/math/vector/byte.hpp b/include/math/vector/byte.hpp new file mode 100644 index 0000000..52fd8ba --- /dev/null +++ b/include/math/vector/byte.hpp @@ -0,0 +1,885 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common unsigned integer 8 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/types.hpp" + +#include +#include +#include +#include + +namespace math +{ + +using namespace std; + +/** + * @brief A 2-component vector of 8-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] byte2 +{ + uint8 x; /**< First vector component. */ + uint8 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 8-bit unsigned integer values. + * @param xy target value for all vector components + */ + constexpr explicit byte2(uint8 xy = 0u) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr byte2(uint8 x, uint8 y) noexcept : x(x), y(y) { } + + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint8& operator[](psize i) noexcept + { + assert(i <= 1); + return ((uint8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint8 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((uint8*)this)[i]; + } + + //****************************************************************************************************************** + constexpr byte2 operator+(byte2 v) const noexcept { return byte2(x + v.x, y + v.y); } + constexpr byte2 operator-(byte2 v) const noexcept { return byte2(x - v.x, y - v.y); } + constexpr byte2 operator*(byte2 v) const noexcept { return byte2(x * v.x, y * v.y); } + constexpr byte2 operator/(byte2 v) const noexcept { return byte2(x / v.x, y / v.y); } + constexpr byte2 operator%(byte2 v) const noexcept { return byte2(x % v.x, y % v.y); } + constexpr byte2 operator&(byte2 v) const noexcept { return byte2(x & v.x, y & v.y); } + constexpr byte2 operator|(byte2 v) const noexcept { return byte2(x | v.x, y | v.y); } + constexpr byte2 operator^(byte2 v) const noexcept { return byte2(x ^ v.x, y ^ v.y); } + constexpr byte2 operator>>(byte2 v) const noexcept { return byte2(x >> v.x, y >> v.y); } + constexpr byte2 operator<<(byte2 v) const noexcept { return byte2(x << v.x, y << v.y); } + constexpr byte2 operator+(uint8 n) const noexcept { return byte2(x + n, y + n); } + constexpr byte2 operator-(uint8 n) const noexcept { return byte2(x - n, y - n); } + constexpr byte2 operator*(uint8 n) const noexcept { return byte2(x * n, y * n); } + constexpr byte2 operator/(uint8 n) const noexcept { return byte2(x / n, y / n); } + constexpr byte2 operator%(uint8 n) const noexcept { return byte2(x % n, y % n); } + constexpr byte2 operator&(uint8 n) const noexcept { return byte2(x & n, y & n); } + constexpr byte2 operator|(uint8 n) const noexcept { return byte2(x | n, y | n); } + constexpr byte2 operator^(uint8 n) const noexcept { return byte2(x ^ n, y ^ n); } + constexpr byte2 operator>>(uint8 n) const noexcept { return byte2(x >> n, y >> n); } + constexpr byte2 operator<<(uint8 n) const noexcept { return byte2(x << n, y << n); } + constexpr byte2 operator-() const noexcept { return byte2(-x, -y); } + constexpr byte2 operator!() const noexcept { return byte2(!x, !y); } + constexpr byte2 operator~() const noexcept { return byte2(~x, ~y); } + byte2& operator+=(byte2 v) noexcept { x += v.x; y += v.y; return *this; } + byte2& operator-=(byte2 v) noexcept { x -= v.x; y -= v.y; return *this; } + byte2& operator*=(byte2 v) noexcept { x *= v.x; y *= v.y; return *this; } + byte2& operator/=(byte2 v) noexcept { x /= v.x; y /= v.y; return *this; } + byte2& operator%=(byte2 v) noexcept { x %= v.x; y %= v.y; return *this; } + byte2& operator&=(byte2 v) noexcept { x &= v.x; y &= v.y; return *this; } + byte2& operator|=(byte2 v) noexcept { x |= v.x; y |= v.y; return *this; } + byte2& operator^=(byte2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + byte2& operator>>=(byte2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + byte2& operator<<=(byte2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + byte2& operator+=(uint8 n) noexcept { x += n; y += n; return *this; } + byte2& operator-=(uint8 n) noexcept { x -= n; y -= n; return *this; } + byte2& operator*=(uint8 n) noexcept { x *= n; y *= n; return *this; } + byte2& operator/=(uint8 n) noexcept { x /= n; y /= n; return *this; } + byte2& operator%=(uint8 n) noexcept { x %= n; y %= n; return *this; } + byte2& operator&=(uint8 n) noexcept { x &= n; y &= n; return *this; } + byte2& operator|=(uint8 n) noexcept { x |= n; y |= n; return *this; } + byte2& operator^=(uint8 n) noexcept { x ^= n; y ^= n; return *this; } + byte2& operator>>=(uint8 n) noexcept { x >>= n; y >>= n; return *this; } + byte2& operator<<=(uint8 n) noexcept { x <<= n; y <<= n; return *this; } + byte2& operator=(uint8 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(byte2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(byte2 v) const noexcept { return x != v.x || y != v.y; } + constexpr byte2 operator<(byte2 v) const noexcept + { + return byte2(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator>(byte2 v) const noexcept + { + return byte2(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator<=(byte2 v) const noexcept + { + return byte2(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator>=(byte2 v) const noexcept + { + return byte2(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0); + } + constexpr bool operator==(uint8 n) const noexcept { return *this == byte2(n); } + constexpr bool operator!=(uint8 n) const noexcept { return *this != byte2(n); } + constexpr byte2 operator<(uint8 n) const noexcept { return *this < byte2(n); } + constexpr byte2 operator>(uint8 n) const noexcept { return *this > byte2(n); } + constexpr byte2 operator<=(uint8 n) const noexcept { return *this <= byte2(n); } + constexpr byte2 operator>=(uint8 n) const noexcept { return *this >= byte2(n); } + + static const byte2 zero, one, max; +}; + +inline const byte2 byte2::zero = byte2(0u); +inline const byte2 byte2::one = byte2(1u); +inline const byte2 byte2::max = byte2(UINT8_MAX); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 8-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] byte3 +{ + uint8 x; /**< First vector component. */ + uint8 y; /**< Second vector component. */ + uint8 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 8-bit unsigned integer values. + * @param xyz target value for all vector components + */ + constexpr explicit byte3(uint8 xyz = 0u) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr byte3(uint8 x, uint8 y, uint8 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 8-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr byte3(byte2 xy, uint8 z) noexcept : x(xy.x), y(xy.y), z(z) { } + /** + * @brief Creates a new 3-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr byte3(uint8 x, byte2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint8& operator[](psize i) noexcept + { + assert(i <= 2); + return ((uint8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint8 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((uint8*)this)[i]; + } + + constexpr explicit operator byte2() const noexcept { return byte2(x, y); } + + //****************************************************************************************************************** + constexpr byte3 operator+(byte3 v) const noexcept { return byte3(x + v.x, y + v.y, z + v.z); } + constexpr byte3 operator-(byte3 v) const noexcept { return byte3(x - v.x, y - v.y, z - v.z); } + constexpr byte3 operator*(byte3 v) const noexcept { return byte3(x * v.x, y * v.y, z * v.z); } + constexpr byte3 operator/(byte3 v) const noexcept { return byte3(x / v.x, y / v.y, z / v.z); } + constexpr byte3 operator%(byte3 v) const noexcept { return byte3(x % v.x, y % v.y, z % v.z); } + constexpr byte3 operator&(byte3 v) const noexcept { return byte3(x & v.x, y & v.y, z & v.z); } + constexpr byte3 operator|(byte3 v) const noexcept { return byte3(x | v.x, y | v.y, z | v.z); } + constexpr byte3 operator^(byte3 v) const noexcept { return byte3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr byte3 operator>>(byte3 v) const noexcept { return byte3(x >> v.x, y >> v.y, z >> v.z); } + constexpr byte3 operator<<(byte3 v) const noexcept { return byte3(x << v.x, y << v.y, z << v.z); } + constexpr byte3 operator+(uint8 n) const noexcept { return byte3(x + n, y + n, z + n); } + constexpr byte3 operator-(uint8 n) const noexcept { return byte3(x - n, y - n, z - n); } + constexpr byte3 operator*(uint8 n) const noexcept { return byte3(x * n, y * n, z * n); } + constexpr byte3 operator/(uint8 n) const noexcept { return byte3(x / n, y / n, z / n); } + constexpr byte3 operator%(uint8 n) const noexcept { return byte3(x % n, y % n, z % n); } + constexpr byte3 operator&(uint8 n) const noexcept { return byte3(x & n, y & n, z & n); } + constexpr byte3 operator|(uint8 n) const noexcept { return byte3(x | n, y | n, z | n); } + constexpr byte3 operator^(uint8 n) const noexcept { return byte3(x ^ n, y ^ n, z ^ n); } + constexpr byte3 operator>>(uint8 n) const noexcept { return byte3(x >> n, y >> n, z >> n); } + constexpr byte3 operator<<(uint8 n) const noexcept { return byte3(x << n, y << n, z << n); } + constexpr byte3 operator-() const noexcept { return byte3(-x, -y, -z); } + constexpr byte3 operator!() const noexcept { return byte3(!x, !y, !z); } + byte3 operator~() const noexcept { return byte3(~x, ~y, ~z); } + byte3& operator+=(byte3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + byte3& operator-=(byte3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + byte3& operator*=(byte3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + byte3& operator/=(byte3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + byte3& operator%=(byte3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + byte3& operator&=(byte3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + byte3& operator|=(byte3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + byte3& operator^=(byte3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + byte3& operator>>=(byte3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + byte3& operator<<=(byte3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + byte3& operator+=(uint8 n) noexcept { x += n; y += n; z += n; return *this; } + byte3& operator-=(uint8 n) noexcept { x -= n; y -= n; z -= n; return *this; } + byte3& operator*=(uint8 n) noexcept { x *= n; y *= n; z *= n; return *this; } + byte3& operator/=(uint8 n) noexcept { x /= n; y /= n; z /= n; return *this; } + byte3& operator%=(uint8 n) noexcept { x %= n; y %= n; z %= n; return *this; } + byte3& operator&=(uint8 n) noexcept { x &= n; y &= n; z &= n; return *this; } + byte3& operator|=(uint8 n) noexcept { x |= n; y |= n; z |= n; return *this; } + byte3& operator^=(uint8 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + byte3& operator>>=(uint8 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + byte3& operator<<=(uint8 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + byte3& operator=(uint8 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(byte3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(byte3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr byte3 operator<(byte3 v) const noexcept + { + return byte3(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0, z < v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator>(byte3 v) const noexcept + { + return byte3(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0, z > v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator<=(byte3 v) const noexcept + { + return byte3(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0, z <= v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator>=(byte3 v) const noexcept + { + return byte3(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0, z >= v.z ? UINT8_MAX : 0); + } + constexpr bool operator==(uint8 n) const noexcept { return *this == byte3(n); } + constexpr bool operator!=(uint8 n) const noexcept { return *this != byte3(n); } + constexpr byte3 operator<(uint8 n) const noexcept { return *this < byte3(n); } + constexpr byte3 operator>(uint8 n) const noexcept { return *this > byte3(n); } + constexpr byte3 operator<=(uint8 n) const noexcept { return *this <= byte3(n); } + constexpr byte3 operator>=(uint8 n) const noexcept { return *this >= byte3(n); } + + static const byte3 zero, one, max; +}; + +inline const byte3 byte3::zero = byte3(0u); +inline const byte3 byte3::one = byte3(1u); +inline const byte3 byte3::max = byte3(UINT8_MAX); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 8-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] byte4 +{ + uint8 x; /**< First vector component. */ + uint8 y; /**< Second vector component. */ + uint8 z; /**< Third vector component. */ + uint8 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit byte4(uint8 xyzw = 0u) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr byte4(uint8 x, uint8 y, uint8 z, uint8 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr byte4(byte2 xy, uint8 z, uint8 w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr byte4(uint8 x, byte2 yz, uint8 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr byte4(uint8 x, uint8 y, byte2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr byte4(byte2 xy, byte2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr byte4(byte3 xyz, uint8 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit unsigned integer values. + * + * @param x first vector component value + * @param yzw second, third and fourth vector component value + */ + constexpr byte4(uint8 x, byte3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint8& operator[](psize i) noexcept + { + assert(i <= 3); + return ((uint8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint8 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((uint8*)this)[i]; + } + + constexpr explicit operator byte3() const noexcept { return byte3(x, y, z); } + constexpr explicit operator byte2() const noexcept { return byte2(x, y); } + + //****************************************************************************************************************** + constexpr byte4 operator+(byte4 v) const noexcept { return byte4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr byte4 operator-(byte4 v) const noexcept { return byte4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr byte4 operator*(byte4 v) const noexcept { return byte4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr byte4 operator/(byte4 v) const noexcept { return byte4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr byte4 operator%(byte4 v) const noexcept { return byte4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr byte4 operator&(byte4 v) const noexcept { return byte4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr byte4 operator|(byte4 v) const noexcept { return byte4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr byte4 operator^(byte4 v) const noexcept { return byte4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr byte4 operator>>(byte4 v) const noexcept { return byte4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr byte4 operator<<(byte4 v) const noexcept { return byte4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr byte4 operator+(uint8 n) const noexcept { return byte4(x + n, y + n, z + n, w + n); } + constexpr byte4 operator-(uint8 n) const noexcept { return byte4(x - n, y - n, z - n, w - n); } + constexpr byte4 operator*(uint8 n) const noexcept { return byte4(x * n, y * n, z * n, w * n); } + constexpr byte4 operator/(uint8 n) const noexcept { return byte4(x / n, y / n, z / n, w / n); } + constexpr byte4 operator%(uint8 n) const noexcept { return byte4(x % n, y % n, z % n, w % n); } + constexpr byte4 operator&(uint8 n) const noexcept { return byte4(x & n, y & n, z & n, w & n); } + constexpr byte4 operator|(uint8 n) const noexcept { return byte4(x | n, y | n, z | n, w | n); } + constexpr byte4 operator^(uint8 n) const noexcept { return byte4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr byte4 operator>>(uint8 n) const noexcept { return byte4(x >> n, y >> n, z >> n, w >> n); } + constexpr byte4 operator<<(uint8 n) const noexcept { return byte4(x << n, y << n, z << n, w << n); } + constexpr byte4 operator-() const noexcept { return byte4(-x, -y, -z, -w); } + constexpr byte4 operator!() const noexcept { return byte4(!x, !y, !z, !w); } + constexpr byte4 operator~() const noexcept { return byte4(~x, ~y, ~z, ~w); } + byte4& operator+=(byte4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + byte4& operator-=(byte4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + byte4& operator*=(byte4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + byte4& operator/=(byte4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + byte4& operator%=(byte4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + byte4& operator&=(byte4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + byte4& operator|=(byte4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + byte4& operator^=(byte4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + byte4& operator>>=(byte4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + byte4& operator<<=(byte4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + byte4& operator+=(uint8 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + byte4& operator-=(uint8 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + byte4& operator*=(uint8 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + byte4& operator/=(uint8 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + byte4& operator%=(uint8 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + byte4& operator&=(uint8 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + byte4& operator|=(uint8 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + byte4& operator^=(uint8 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + byte4& operator>>=(uint8 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + byte4& operator<<=(uint8 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + byte4& operator=(uint8 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(byte4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(byte4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr byte4 operator<(byte4 v) const noexcept + { + return byte4(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0, + z < v.z ? UINT8_MAX : 0, w < v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator>(byte4 v) const noexcept + { + return byte4(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0, + z > v.z ? UINT8_MAX : 0, w > v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator<=(byte4 v) const noexcept + { + return byte4(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0, + z <= v.z ? UINT8_MAX : 0, w <= v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator>=(byte4 v) const noexcept + { + return byte4(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0, + z >= v.z ? UINT8_MAX : 0, w >= v.w ? UINT8_MAX : 0); + } + constexpr bool operator==(uint8 n) const noexcept { return *this == byte4(n); } + constexpr bool operator!=(uint8 n) const noexcept { return *this != byte4(n); } + constexpr byte4 operator<(uint8 n) const noexcept { return *this < byte4(n); } + constexpr byte4 operator>(uint8 n) const noexcept { return *this > byte4(n); } + constexpr byte4 operator<=(uint8 n) const noexcept { return *this <= byte4(n); } + constexpr byte4 operator>=(uint8 n) const noexcept { return *this >= byte4(n); } + + static const byte4 zero, one, max; +}; + +inline const byte4 byte4::zero = byte4(0u); +inline const byte4 byte4::one = byte4(1u); +inline const byte4 byte4::max = byte4(UINT8_MAX); + +//********************************************************************************************************************** +static constexpr byte2 operator+(uint8 n, byte2 v) noexcept { return byte2(n) + v; } +static constexpr byte2 operator-(uint8 n, byte2 v) noexcept { return byte2(n) - v; } +static constexpr byte2 operator*(uint8 n, byte2 v) noexcept { return byte2(n) * v; } +static constexpr byte2 operator/(uint8 n, byte2 v) noexcept { return byte2(n) / v; } +static constexpr byte2 operator%(uint8 n, byte2 v) noexcept { return byte2(n) % v; } +static constexpr byte2 operator&(uint8 n, byte2 v) noexcept { return byte2(n) & v; } +static constexpr byte2 operator|(uint8 n, byte2 v) noexcept { return byte2(n) | v; } +static constexpr byte2 operator^(uint8 n, byte2 v) noexcept { return byte2(n) ^ v; } +static constexpr byte2 operator>>(uint8 n, byte2 v) noexcept { return byte2(n) >> v; } +static constexpr byte2 operator<<(uint8 n, byte2 v) noexcept { return byte2(n) << v; } +static constexpr bool operator==(uint8 n, byte2 v) noexcept { return byte2(n) == v; } +static constexpr bool operator!=(uint8 n, byte2 v) noexcept { return byte2(n) != v; } +static constexpr byte2 operator<(uint8 n, byte2 v) noexcept { return byte2(n) < v; } +static constexpr byte2 operator>(uint8 n, byte2 v) noexcept { return byte2(n) > v; } +static constexpr byte2 operator<=(uint8 n, byte2 v) noexcept { return byte2(n) <= v; } +static constexpr byte2 operator>=(uint8 n, byte2 v) noexcept { return byte2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(byte2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (2bits) + */ +static constexpr uint8 getTrues(byte2 v) noexcept +{ + return (v.x >> 7u) | ((v.y >> 7u) << 1u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(byte2 v) noexcept { return (v.x & v.y) == UINT8_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(byte2 v) noexcept { return (v.x | v.y) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(byte2 v) noexcept { return v.x | v.y; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(byte2 v) noexcept { return (v.x & v.y) != UINT8_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte2 equal(byte2 a, byte2 b) noexcept +{ + return byte2(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte2 notEqual(byte2 a, byte2 b) noexcept +{ + return byte2(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(byte2 a, byte2 b) noexcept { return *((const uint16*)&a) < *((const uint16*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr byte2 select(byte2 c, byte2 t, byte2 f) noexcept +{ + return byte2(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr byte2 min(byte2 a, byte2 b) noexcept +{ + return byte2(std::min(a.x, b.x), std::min(a.y, b.y)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr byte2 max(byte2 a, byte2 b) noexcept +{ + return byte2(std::max(a.x, b.x), std::max(a.y, b.y)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr byte2 min(byte2 a, byte2 b, byte2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr byte2 max(byte2 a, byte2 b, byte2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr byte2 clamp(byte2 v, byte2 min, byte2 max) noexcept +{ + return byte2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr byte3 operator+(uint8 n, byte3 v) noexcept { return byte3(n) + v; } +static constexpr byte3 operator-(uint8 n, byte3 v) noexcept { return byte3(n) - v; } +static constexpr byte3 operator*(uint8 n, byte3 v) noexcept { return byte3(n) * v; } +static constexpr byte3 operator/(uint8 n, byte3 v) noexcept { return byte3(n) / v; } +static constexpr byte3 operator%(uint8 n, byte3 v) noexcept { return byte3(n) % v; } +static constexpr byte3 operator&(uint8 n, byte3 v) noexcept { return byte3(n) & v; } +static constexpr byte3 operator|(uint8 n, byte3 v) noexcept { return byte3(n) | v; } +static constexpr byte3 operator^(uint8 n, byte3 v) noexcept { return byte3(n) ^ v; } +static constexpr byte3 operator>>(uint8 n, byte3 v) noexcept { return byte3(n) >> v; } +static constexpr byte3 operator<<(uint8 n, byte3 v) noexcept { return byte3(n) << v; } +static constexpr bool operator==(uint8 n, byte3 v) noexcept { return byte3(n) == v; } +static constexpr bool operator!=(uint8 n, byte3 v) noexcept { return byte3(n) != v; } +static constexpr byte3 operator<(uint8 n, byte3 v) noexcept { return byte3(n) < v; } +static constexpr byte3 operator>(uint8 n, byte3 v) noexcept { return byte3(n) > v; } +static constexpr byte3 operator<=(uint8 n, byte3 v) noexcept { return byte3(n) <= v; } +static constexpr byte3 operator>=(uint8 n, byte3 v) noexcept { return byte3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(byte3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (3bits) + */ +static constexpr uint8 getTrues(byte3 v) noexcept +{ + return (v.x >> 7u) | ((v.y >> 7u) << 1u) | ((v.z >> 7u) << 2u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(byte3 v) noexcept { return (v.x & v.y & v.z) == UINT8_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(byte3 v) noexcept { return (v.x | v.y | v.z) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(byte3 v) noexcept { return v.x | v.y | v.z; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(byte3 v) noexcept { return (v.x & v.y & v.z) != UINT8_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte3 equal(byte3 a, byte3 b) noexcept +{ + return byte3(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0, a.z == b.z ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte3 notEqual(byte3 a, byte3 b) noexcept +{ + return byte3(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0, a.z != b.z ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const byte3& a, const byte3& b) noexcept { return memcmp(&a, &b, sizeof(byte3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr byte3 select(byte3 c, byte3 t, byte3 f) noexcept +{ + return byte3(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y, c.z & 0x80u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr byte3 min(byte3 a, byte3 b) noexcept +{ + return byte3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr byte3 max(byte3 a, byte3 b) noexcept +{ + return byte3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr byte3 min(byte3 a, byte3 b, byte3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr byte3 max(byte3 a, byte3 b, byte3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr byte3 clamp(byte3 v, byte3 min, byte3 max) noexcept +{ + return byte3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr byte4 operator+(uint8 n, const byte4& v) noexcept { return byte4(n) + v; } +static constexpr byte4 operator-(uint8 n, const byte4& v) noexcept { return byte4(n) - v; } +static constexpr byte4 operator*(uint8 n, const byte4& v) noexcept { return byte4(n) * v; } +static constexpr byte4 operator/(uint8 n, const byte4& v) noexcept { return byte4(n) / v; } +static constexpr byte4 operator%(uint8 n, const byte4& v) noexcept { return byte4(n) % v; } +static constexpr byte4 operator&(uint8 n, const byte4& v) noexcept { return byte4(n) & v; } +static constexpr byte4 operator|(uint8 n, const byte4& v) noexcept { return byte4(n) | v; } +static constexpr byte4 operator^(uint8 n, const byte4& v) noexcept { return byte4(n) ^ v; } +static constexpr byte4 operator>>(uint8 n, const byte4& v) noexcept { return byte4(n) >> v; } +static constexpr byte4 operator<<(uint8 n, const byte4& v) noexcept { return byte4(n) << v; } +static constexpr bool operator==(uint8 n, const byte4& v) noexcept { return byte4(n) == v; } +static constexpr bool operator!=(uint8 n, const byte4& v) noexcept { return byte4(n) != v; } +static constexpr byte4 operator<(uint8 n, const byte4& v) noexcept { return byte4(n) < v; } +static constexpr byte4 operator>(uint8 n, const byte4& v) noexcept { return byte4(n) > v; } +static constexpr byte4 operator<=(uint8 n, const byte4& v) noexcept { return byte4(n) <= v; } +static constexpr byte4 operator>=(uint8 n, const byte4& v) noexcept { return byte4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(byte4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (4bits) + */ +static constexpr uint8 getTrues(byte4 v) noexcept +{ + return (v.x >> 7u) | ((v.y >> 7u) << 1u) | ((v.z >> 7u) << 2u) | ((v.w >> 7u) << 3u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(byte4 v) noexcept { return (v.x & v.y & v.z & v.w) == UINT8_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(byte4 v) noexcept { return (v.x | v.y | v.z | v.w) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(byte4 v) noexcept { return v.x | v.y | v.z | v.w; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(byte4 v) noexcept { return (v.x & v.y & v.z & v.w) != UINT8_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte4 equal(byte4 a, byte4 b) noexcept +{ + return byte4(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0, + a.z == b.z ? UINT8_MAX : 0, a.w == b.w ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte4 notEqual(byte4 a, byte4 b) noexcept +{ + return byte4(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0, + a.z != b.z ? UINT8_MAX : 0, a.w != b.w ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const byte4& a, const byte4& b) noexcept +{ + return *((const uint32*)&a) < *((const uint32*)&b); +} + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr byte4 select(byte4 c, byte4 t, byte4 f) noexcept +{ + return byte4(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y, c.z & 0x80u ? t.z : f.z, c.w & 0x80u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr byte4 min(byte4 a, byte4 b) noexcept +{ + return byte4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr byte4 max(byte4 a, byte4 b) noexcept +{ + return byte4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr byte4 min(byte4 a, byte4 b, byte4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr byte4 max(byte4 a, byte4 b, byte4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr byte4 clamp(byte4 v, byte4 min, byte4 max) noexcept +{ + return byte4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/double.hpp b/include/math/vector/double.hpp new file mode 100644 index 0000000..5a220d5 --- /dev/null +++ b/include/math/vector/double.hpp @@ -0,0 +1,1665 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common floating point 64 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/common.hpp" +#include "math/vector/half.hpp" + +namespace math +{ + +/** + * @brief A 2-component vector of 64-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] double2 +{ + double x; /**< First vector component. */ + double y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy target value for all vector components + */ + constexpr explicit double2(double xy = 0.0) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr double2(double x, double y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr double2(half2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr double2(long2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr double2(ulong2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr double2(int2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr double2(uint2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr double2(short2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr double2(ushort2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr double2(sbyte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr double2(byte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + double& operator[](psize i) noexcept + { + assert(i <= 1); + return ((double*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + double operator[](psize i) const noexcept + { + assert(i <= 1); + return ((double*)this)[i]; + } + + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr double2 operator+(double2 v) const noexcept { return double2(x + v.x, y + v.y); } + constexpr double2 operator-(double2 v) const noexcept { return double2(x - v.x, y - v.y); } + constexpr double2 operator*(double2 v) const noexcept { return double2(x * v.x, y * v.y); } + constexpr double2 operator/(double2 v) const noexcept { return double2(x / v.x, y / v.y); } + constexpr double2 operator+(double n) const noexcept { return double2(x + n, y + n); } + constexpr double2 operator-(double n) const noexcept { return double2(x - n, y - n); } + constexpr double2 operator*(double n) const noexcept { return double2(x * n, y * n); } + constexpr double2 operator/(double n) const noexcept { return double2(x / n, y / n); } + constexpr double2 operator-() const noexcept { return double2(-x, -y); } + double2& operator+=(double2 v) noexcept { x += v.x; y += v.y; return *this; } + double2& operator-=(double2 v) noexcept { x -= v.x; y -= v.y; return *this; } + double2& operator*=(double2 v) noexcept { x *= v.x; y *= v.y; return *this; } + double2& operator/=(double2 v) noexcept { x /= v.x; y /= v.y; return *this; } + double2& operator+=(double n) noexcept { x += n; y += n; return *this; } + double2& operator-=(double n) noexcept { x -= n; y -= n; return *this; } + double2& operator*=(double n) noexcept { x *= n; y *= n; return *this; } + double2& operator/=(double n) noexcept { x /= n; y /= n; return *this; } + double2& operator=(double n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(double2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(double2 v) const noexcept { return x != v.x || y != v.y; } + constexpr uint2 operator<(double2 v) const noexcept + { + return uint2(x < v.x ? UINT32_MAX : 0, y < v.y ? UINT32_MAX : 0); + } + constexpr uint2 operator>(double2 v) const noexcept + { + return uint2(x > v.x ? UINT32_MAX : 0, y > v.y ? UINT32_MAX : 0); + } + constexpr uint2 operator<=(double2 v) const noexcept + { + return uint2(x <= v.x ? UINT32_MAX : 0, y <= v.y ? UINT32_MAX : 0); + } + constexpr uint2 operator>=(double2 v) const noexcept + { + return uint2(x >= v.x ? UINT32_MAX : 0, y >= v.y ? UINT32_MAX : 0); + } + constexpr bool operator==(double n) const noexcept { return *this == double2(n); } + constexpr bool operator!=(double n) const noexcept { return *this != double2(n); } + constexpr uint2 operator<(double n) const noexcept { return *this < double2(n); } + constexpr uint2 operator>(double n) const noexcept { return *this > double2(n); } + constexpr uint2 operator<=(double n) const noexcept { return *this <= double2(n); } + constexpr uint2 operator>=(double n) const noexcept { return *this >= double2(n); } + + static const double2 zero, one, minusOne, min, minusMin, max, minusMax, + epsilon, inf, minusInf, nan, left, right, bottom, top; +}; + +inline constexpr double2 double2::zero = double2(0.0); +inline constexpr double2 double2::one = double2(1.0); +inline constexpr double2 double2::minusOne = double2(-1.0); +inline constexpr double2 double2::min = double2(DBL_MIN); +inline constexpr double2 double2::minusMin = double2(-DBL_MIN); +inline constexpr double2 double2::max = double2(DBL_MAX); +inline constexpr double2 double2::minusMax = double2(-DBL_MAX); +inline constexpr double2 double2::epsilon = double2(FLT_EPSILON); +inline constexpr double2 double2::inf = double2(INFINITY); +inline constexpr double2 double2::minusInf = double2(-INFINITY); +inline constexpr double2 double2::nan = double2(NAN); +inline constexpr double2 double2::left = double2(-1.0, 0.0); +inline constexpr double2 double2::right = double2(1.0, 0.0); +inline constexpr double2 double2::bottom = double2(0.0, -1.0); +inline constexpr double2 double2::top = double2(0.0, 1.0); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 64-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] double3 +{ + double x; /**< First vector component. */ + double y; /**< Second vector component. */ + double z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz target value for all vector components + */ + constexpr explicit double3(double xyz = 0.0) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr double3(double x, double y, double z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr double3(double2 xy, double z) noexcept : x(xy.x), y(xy.y), z(z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr double3(double x, double2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr double3(half3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr double3(long3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr double3(ulong3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr double3(int3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr double3(uint3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr double3(short3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr double3(ushort3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr double3(sbyte3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr double3(byte3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + double& operator[](psize i) noexcept + { + assert(i <= 2); + return ((double*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + double operator[](psize i) const noexcept + { + assert(i <= 2); + return ((double*)this)[i]; + } + + constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator double2() const noexcept { return double2(x, y); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr double3 operator+(double3 v) const noexcept { return double3(x + v.x, y + v.y, z + v.z); } + constexpr double3 operator-(double3 v) const noexcept { return double3(x - v.x, y - v.y, z - v.z); } + constexpr double3 operator*(double3 v) const noexcept { return double3(x * v.x, y * v.y, z * v.z); } + constexpr double3 operator/(double3 v) const noexcept { return double3(x / v.x, y / v.y, z / v.z); } + constexpr double3 operator+(double n) const noexcept { return double3(x + n, y + n, z + n); } + constexpr double3 operator-(double n) const noexcept { return double3(x - n, y - n, z - n); } + constexpr double3 operator*(double n) const noexcept { return double3(x * n, y * n, z * n); } + constexpr double3 operator/(double n) const noexcept { return double3(x / n, y / n, z / n); } + constexpr double3 operator-() const noexcept { return double3(-x, -y, -z); } + double3& operator+=(double3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + double3& operator-=(double3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + double3& operator*=(double3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + double3& operator/=(double3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + double3& operator+=(double n) noexcept { x += n; y += n; z += n; return *this; } + double3& operator-=(double n) noexcept { x -= n; y -= n; z -= n; return *this; } + double3& operator*=(double n) noexcept { x *= n; y *= n; z *= n; return *this; } + double3& operator/=(double n) noexcept { x /= n; y /= n; z /= n; return *this; } + double3& operator=(double n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(double3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(double3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr uint3 operator<(double3 v) const noexcept + { + return uint3(x < v.x ? UINT32_MAX : 0, y < v.y ? UINT32_MAX : 0, z < v.z ? UINT32_MAX : 0); + } + constexpr uint3 operator>(double3 v) const noexcept + { + return uint3(x > v.x ? UINT32_MAX : 0, y > v.y ? UINT32_MAX : 0, z > v.z ? UINT32_MAX : 0); + } + constexpr uint3 operator<=(double3 v) const noexcept + { + return uint3(x <= v.x ? UINT32_MAX : 0, y <= v.y ? UINT32_MAX : 0, z <= v.z ? UINT32_MAX : 0); + } + constexpr uint3 operator>=(double3 v) const noexcept + { + return uint3(x >= v.x ? UINT32_MAX : 0, y >= v.y ? UINT32_MAX : 0, z >= v.z ? UINT32_MAX : 0); + } + constexpr bool operator==(double n) const noexcept { return *this == double3(n); } + constexpr bool operator!=(double n) const noexcept { return *this != double3(n); } + constexpr uint3 operator<(double n) const noexcept { return *this < double3(n); } + constexpr uint3 operator>(double n) const noexcept { return *this > double3(n); } + constexpr uint3 operator<=(double n) const noexcept { return *this <= double3(n); } + constexpr uint3 operator>=(double n) const noexcept { return *this >= double3(n); } + + static const double3 zero, one, minusOne, min, minusMin, max, minusMax, + epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; +}; + +inline constexpr double3 double3::zero = double3(0.0); +inline constexpr double3 double3::one = double3(1.0); +inline constexpr double3 double3::minusOne = double3(-1.0); +inline constexpr double3 double3::min = double3(DBL_MIN); +inline constexpr double3 double3::minusMin = double3(-DBL_MIN); +inline constexpr double3 double3::max = double3(DBL_MAX); +inline constexpr double3 double3::minusMax = double3(-DBL_MAX); +inline constexpr double3 double3::epsilon = double3(FLT_EPSILON); +inline constexpr double3 double3::inf = double3(INFINITY); +inline constexpr double3 double3::minusInf = double3(-INFINITY); +inline constexpr double3 double3::nan = double3(NAN); +inline constexpr double3 double3::left = double3(-1.0, 0.0, 0.0); +inline constexpr double3 double3::right = double3(1.0, 0.0, 0.0); +inline constexpr double3 double3::bottom = double3(0.0, -1.0, 0.0); +inline constexpr double3 double3::top = double3(0.0, 1.0, 0.0); +inline constexpr double3 double3::back = double3(0.0, 0.0, -1.0); +inline constexpr double3 double3::front = double3(0.0, 0.0, 1.0); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 64-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] double4 +{ + double x; /**< First vector component. */ + double y; /**< Second vector component. */ + double z; /**< Third vector component. */ + double w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw target value for all vector components + */ + constexpr explicit double4(double xyzw = 0.0) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr double4(double x, double y, double z, double w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr double4(double2 xy, double z, double w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr double4(double x, double2 yz, double w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr double4(double x, double y, double2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr double4(double2 xy, double2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr double4(double3 xyz, double w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * + * @param x first vector component value + * @param yzw second, third and fourth vector component value + */ + constexpr double4(double x, double3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr double4(half4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr double4(long4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr double4(ulong4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr double4(int4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr double4(uint4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr double4(short4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr double4(ushort4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr double4(sbyte4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr double4(byte4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + double& operator[](psize i) noexcept + { + assert(i <= 3); + return ((double*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + double operator[](psize i) const noexcept + { + assert(i <= 3); + return ((double*)this)[i]; + } + + constexpr explicit operator half4() const noexcept { return half4((half)x, (half)y, (half)z, (half)w); } + constexpr explicit operator long4() const noexcept { return long4((int64)x, (int64)y, (int64)z, (int64)w); } + constexpr explicit operator ulong4() const noexcept { return ulong4((uint64)x, (uint64)y, (uint64)z, (uint64)w); } + constexpr explicit operator int4() const noexcept { return int4((int32)x, (int32)y, (int32)z, (int32)w); } + constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator double3() const noexcept { return double3(x, y, z); } + constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator double2() const noexcept { return double2(x, y); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr double4 operator+(double4 v) const noexcept { return double4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr double4 operator-(double4 v) const noexcept { return double4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr double4 operator*(double4 v) const noexcept { return double4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr double4 operator/(double4 v) const noexcept { return double4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr double4 operator+(double n) const noexcept { return double4(x + n, y + n, z + n, w + n); } + constexpr double4 operator-(double n) const noexcept { return double4(x - n, y - n, z - n, w - n); } + constexpr double4 operator*(double n) const noexcept { return double4(x * n, y * n, z * n, w * n); } + constexpr double4 operator/(double n) const noexcept { return double4(x / n, y / n, z / n, w / n); } + constexpr double4 operator-() const noexcept { return double4(-x, -y, -z, -w); } + double4& operator+=(double4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + double4& operator-=(double4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + double4& operator*=(double4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + double4& operator/=(double4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + double4& operator+=(double n) noexcept { x += n; y += n; z += n; w += n; return *this; } + double4& operator-=(double n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + double4& operator*=(double n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + double4& operator/=(double n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + double4& operator=(double n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(double4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(double4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr uint4 operator<(double4 v) const noexcept + { + return uint4(x < v.x ? UINT32_MAX : 0, y < v.y ? UINT32_MAX : 0, + z < v.z ? UINT32_MAX : 0, w < v.w ? UINT32_MAX : 0); + } + constexpr uint4 operator>(double4 v) const noexcept + { + return uint4(x > v.x ? UINT32_MAX : 0, y > v.y ? UINT32_MAX : 0, + z > v.z ? UINT32_MAX : 0, w > v.w ? UINT32_MAX : 0); + } + constexpr uint4 operator<=(double4 v) const noexcept + { + return uint4(x <= v.x ? UINT32_MAX : 0, y <= v.y ? UINT32_MAX : 0, + z <= v.z ? UINT32_MAX : 0, w <= v.w ? UINT32_MAX : 0); + } + constexpr uint4 operator>=(double4 v) const noexcept + { + return uint4(x >= v.x ? UINT32_MAX : 0, y >= v.y ? UINT32_MAX : 0, + z >= v.z ? UINT32_MAX : 0, w >= v.w ? UINT32_MAX : 0); + } + constexpr bool operator==(double n) const noexcept { return *this == double4(n); } + constexpr bool operator!=(double n) const noexcept { return *this != double4(n); } + constexpr uint4 operator<(double n) const noexcept { return *this < double4(n); } + constexpr uint4 operator>(double n) const noexcept { return *this > double4(n); } + constexpr uint4 operator<=(double n) const noexcept { return *this <= double4(n); } + constexpr uint4 operator>=(double n) const noexcept { return *this >= double4(n); } + + static const double4 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan; +}; + +inline constexpr double4 double4::zero = double4(0.0); +inline constexpr double4 double4::one = double4(1.0); +inline constexpr double4 double4::minusOne = double4(-1.0); +inline constexpr double4 double4::min = double4(DBL_MIN); +inline constexpr double4 double4::minusMin = double4(-DBL_MIN); +inline constexpr double4 double4::max = double4(DBL_MAX); +inline constexpr double4 double4::minusMax = double4(-DBL_MAX); +inline constexpr double4 double4::epsilon = double4(FLT_EPSILON); +inline constexpr double4 double4::inf = double4(INFINITY); +inline constexpr double4 double4::minusInf = double4(-INFINITY); +inline constexpr double4 double4::nan = double4(NAN); + +//********************************************************************************************************************** +static constexpr double2 operator+(double n, double2 v) noexcept { return double2(n) + v; } +static constexpr double2 operator-(double n, double2 v) noexcept { return double2(n) - v; } +static constexpr double2 operator*(double n, double2 v) noexcept { return double2(n) * v; } +static constexpr double2 operator/(double n, double2 v) noexcept { return double2(n) / v; } +static constexpr bool operator==(double n, double2 v) noexcept { return double2(n) == v; } +static constexpr bool operator!=(double n, double2 v) noexcept { return double2(n) != v; } +static constexpr uint2 operator<(double n, double2 v) noexcept { return double2(n) < v; } +static constexpr uint2 operator>(double n, double2 v) noexcept { return double2(n) > v; } +static constexpr uint2 operator<=(double n, double2 v) noexcept { return double2(n) <= v; } +static constexpr uint2 operator>=(double n, double2 v) noexcept { return double2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(double2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint2 equal(double2 a, double4 b) noexcept +{ + return uint2(a.x == b.x ? UINT32_MAX : 0, a.y == b.y ? UINT32_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint2 notEqual(double2 a, double4 b) noexcept +{ + return uint2(a.x != b.x ? UINT32_MAX : 0, a.y != b.y ? UINT32_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(double2 a, double2 b) noexcept { return *((const int64*)&a) < *((const int64*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr double2 select(uint2 c, double2 t, double2 f) noexcept +{ + return double2(c.x & 0x80000000u ? t.x : f.x, c.y & 0x80000000u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr double2 min(double2 a, double2 b) noexcept { return double2(std::min(a.x, b.x), std::min(a.y, b.y)); } +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr double2 max(double2 a, double2 b) noexcept { return double2(std::max(a.x, b.x), std::max(a.y, b.y)); } +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr double2 min(double2 a, double2 b, double2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr double2 max(double2 a, double2 b, double2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. (Inclusive range) + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr double2 clamp(double2 v, double2 min, double2 max) noexcept +{ + return double2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} +/** + * @brief Clamps vector components between the 0.0 and 1.0. (Inclusive range) + * @param v target vector to saturate + */ +static constexpr double2 saturate(double2 v) noexcept +{ + return double2(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0)); +} + +/*********************************************************************************************************************** + * @brief Fused multiply add, calculates: mul1 * mul2 + add + * + * @param mul1 first vector multiplier + * @param mul2 second vector multiplier + * @param add vector addend + */ +static double2 fma(double2 mul1, double2 mul2, double2 add) noexcept +{ + return double2(std::fma(mul1.x, mul2.x, add.x), std::fma(mul1.y, mul2.y, add.y)); +} +/** + * @brief Returns absolute value for each component of the vector. + * @param v target vector + */ +static double2 abs(double2 v) noexcept { return double2(std::abs(v.x), std::abs(v.y)); } +/** + * @brief Returns square root for each component of the vector. + * @param v target vector + */ +static double2 sqrt(double2 v) noexcept { return double2(std::sqrt(v.x), std::sqrt(v.y)); } +/** + * @brief Returns sign for each component of the vector. + * @param v target vector + */ +static double2 sign(double2 v) noexcept { return double2(sign(v.x), sign(v.y)); } +/** + * @brief Returns sign bits of the vector. (2 bits) + * @param v target vector + */ +static uint32 signBits(double2 v) noexcept { return (std::signbit(v.x) ? 1u : 0u) | (std::signbit(v.y) ? 2u : 0u); } + +/** + * @brief Returns index of the highest vector component value. + * @param v target vector + */ +static constexpr uint32 getHighest(double2 v) noexcept { return v.x > v.y ? 0 : 1; } +/** + * @brief Returns index of the lowest vector component value. + * @param v target vector + */ +static constexpr uint32 getLowest3(double2 v) noexcept { return v.x < v.y ? 0 : 1; } + +/** + * @brief Rounds each component of the vector to nearest integer. (1.5 -> 2.0; -1.5 -> -2.0) + * @param v target vector + */ +static double2 round(double2 v) noexcept { return double2(std::round(v.x), std::round(v.y)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.7 -> -2.0) + * @param v target vector + */ +static double2 floor(double2 v) noexcept { return double2(std::floor(v.x), std::floor(v.y)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.4 -> 2.0; -1.4 -> -1.0) + * @param v target vector + */ +static double2 ceil(double2 v) noexcept { return double2(std::ceil(v.x), std::ceil(v.y)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.9 -> -1.0) + * @param v target vector + */ +static double2 trunc(double2 v) noexcept { return double2(std::trunc(v.x), std::trunc(v.y)); } + +/*********************************************************************************************************************** + * @brief Returns dot product between two vector. + * + * @param a first vector to dot + * @param b second vector to dot + */ +static constexpr double dot(double2 a, double2 b) noexcept { return a.x * b.x + a.y * b.y; } + +/** + * @brief Returns squared length of the vector. (length ^ 2) + * @note Faster to compute because we don't calculate square root. + * @param v target vector + */ +static constexpr double lengthSq(double2 v) noexcept { return dot(v, v); } +/** + * @brief Returns length of the vector. + * @param v target vector + */ +static double length(double2 v) noexcept { return std::sqrt(dot(v, v)); } + +/** + * @brief Returns squared distance between two points. (distance ^ 2) + * @note Faster to compute because we don't calculate square root. + * + * @param a first point + * @param b second point + */ +static constexpr double distanceSq(double2 a, double2 b) noexcept { return lengthSq(a - b); } +/** + * @brief Returns distance between two points. + * + * @param a first point + * @param b second point + */ +static double distance(double2 a, double2 b) noexcept { return length(a - b); } +/** + * @brief Returns true if two vectors are close with specified maximum squared distance. (maxDistance ^ 2) + * + * @param a first vector + * @param b second vector + */ +static constexpr bool isClose(double2 a, double2 b, double maxDistSq = 1.0e-12f) noexcept +{ + return distanceSq(a, b) <= maxDistSq; +} + +/** + * @brief Returns normalized vector. (With length of 1.0) + * @param v target vector to normalize + */ +static double2 normalize(double2 v) noexcept { return v * (1.0 / length(v)); } +/** + * @brief Returns true if vector is normalized with specified tolerance. + * + * @param v target vector to check + * @param tolerance floating point precision tolerance + */ +static bool isNormalized(double2 v, double tolerance = 1.0e-6f) noexcept +{ + return std::abs(lengthSq(v) - 1.0) <= tolerance; +} +/** + * @brief Returns true if any vector element is not a number. + * @param v target vector to check + */ +static bool isNan(double2 v) noexcept { return isnan(v.x) || isnan(v.y); } + +/** + * @brief Remaps each component of vector to the 0.0 - 1.0 range. + * @param v target vector + */ +static double2 repeat(double2 v) noexcept { return double2(repeat(v.x), repeat(v.y)); } + +/** + * @brief Linearly interpolates each component of the vector between a and b using t. + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + */ +static double2 lerp(double2 a, double2 b, double t) noexcept { return a * (1.0 - t) + b * t; } +/** + * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @note Always use this function instead of basic lerp() when you have variable delta time! + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + * @param dt current delta time + */ +static double2 lerpDelta(double2 a, double2 b, double f, double dt) noexcept +{ + return a + (1.0 - std::pow(f, dt)) * (b - a); +} + +/** + * @brief Computes the power of each component of base b raised to the corresponding exponent e. + * + * @param b target base vector to raise + * @param e exponent vector + */ +static double2 pow(double2 b, double2 e) noexcept { return double2(std::pow(b.x, e.x), std::pow(b.y, e.y)); } +/** + * @brief Applies gain function for each component of the vector. + * @note The function is symmetric when x == 0.5. + * + * @param x target vector to gain (0.0 - 1.0) + * @param k gain factor + */ +static double2 gain(double2 x, double2 k) noexcept +{ + auto a = double2(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); + return select(x < 0.5f, a, 1.0 - a); +} + +//********************************************************************************************************************** +static constexpr double3 operator+(double n, double3 v) noexcept { return double3(n) + v; } +static constexpr double3 operator-(double n, double3 v) noexcept { return double3(n) - v; } +static constexpr double3 operator*(double n, double3 v) noexcept { return double3(n) * v; } +static constexpr double3 operator/(double n, double3 v) noexcept { return double3(n) / v; } +static constexpr bool operator==(double n, double3 v) noexcept { return double3(n) == v; } +static constexpr bool operator!=(double n, double3 v) noexcept { return double3(n) != v; } +static constexpr uint3 operator<(double n, double3 v) noexcept { return double3(n) < v; } +static constexpr uint3 operator>(double n, double3 v) noexcept { return double3(n) > v; } +static constexpr uint3 operator<=(double n, double3 v) noexcept { return double3(n) <= v; } +static constexpr uint3 operator>=(double n, double3 v) noexcept { return double3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(double3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint3 equal(double3 a, double3 b) noexcept +{ + return uint3(a.x == b.x ? UINT32_MAX : 0, a.y == b.y ? UINT32_MAX : 0, a.z == b.z ? UINT32_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint3 notEqual(double3 a, double3 b) noexcept +{ + return uint3(a.x != b.x ? UINT32_MAX : 0, a.y != b.y ? UINT32_MAX : 0, a.z != b.z ? UINT32_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const double3& a, const double3& b) noexcept { return memcmp(&a, &b, sizeof(double3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr double3 select(uint3 c, double3 t, double3 f) noexcept +{ + return double3(c.x & 0x80000000u ? t.x : f.x, c.y & 0x80000000u ? t.y : f.y, c.z & 0x80000000u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr double3 min(double3 a, double3 b) noexcept +{ + return double3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr double3 max(double3 a, double3 b) noexcept +{ + return double3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr double3 min(double3 a, double3 b, double3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr double3 max(double3 a, double3 b, double3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. (Inclusive range) + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr double3 clamp(double3 v, double3 min, double3 max) noexcept +{ + return double3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} +/** + * @brief Clamps vector components between the 0.0 and 1.0. (Inclusive range) + * @param v target vector to saturate + */ +static constexpr double3 saturate(double3 v) noexcept +{ + return double3(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0), std::clamp(v.z, 0.0, 1.0)); +} + +/*********************************************************************************************************************** + * @brief Fused multiply add, calculates: mul1 * mul2 + add + * + * @param mul1 first vector multiplier + * @param mul2 second vector multiplier + * @param add vector addend + */ +static double3 fma(double3 mul1, double3 mul2, double3 add) noexcept +{ + return double3(std::fma(mul1.x, mul2.x, add.x), std::fma(mul1.y, mul2.y, add.y), std::fma(mul1.z, mul2.z, add.z)); +} +/** + * @brief Returns absolute value for each component of the vector. + * @param v target vector + */ +static double3 abs(double3 v) noexcept { return double3(std::abs(v.x), std::abs(v.y), std::abs(v.z)); } +/** + * @brief Returns square root for each component of the vector. + * @param v target vector + */ +static double3 sqrt(double3 v) noexcept { return double3(std::sqrt(v.x), std::sqrt(v.y), std::sqrt(v.z)); } +/** + * @brief Returns sign for each component of the vector. + * @param v target vector + */ +static double3 sign(double3 v) noexcept { return double3(sign(v.x), sign(v.y), sign(v.z)); } +/** + * @brief Returns sign bits of the vector. (3 bits) + * @param v target vector + */ +static uint32 signBits(double3 v) noexcept +{ + return (std::signbit(v.x) ? 1u : 0u) | (std::signbit(v.y) ? 2u : 0u) | (std::signbit(v.z) ? 4u : 0u); +} + +/** + * @brief Returns index of the highest vector component value. + * @param v target vector + */ +static constexpr uint32 getHighest(double3 v) noexcept { return v.x > v.y ? (v.z > v.x ? 2 : 0) : (v.z > v.y ? 2 : 1); } +/** + * @brief Returns index of the lowest vector component value. + * @param v target vector + */ +static constexpr uint32 getLowest(double3 v) noexcept { return v.x < v.y ? (v.z < v.x ? 2 : 0) : (v.z < v.y ? 2 : 1); } + +/** + * @brief Rounds each component of the vector to nearest integer. (1.5 -> 2.0; -1.5 -> -2.0) + * @param v target vector + */ +static double3 round(double3 v) noexcept { return double3(std::round(v.x), std::round(v.y), std::round(v.z)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.7 -> -2.0) + * @param v target vector + */ +static double3 floor(double3 v) noexcept { return double3(std::floor(v.x), std::floor(v.y), std::floor(v.z)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.4 -> 2.0; -1.4 -> -1.0) + * @param v target vector + */ +static double3 ceil(double3 v) noexcept { return double3(std::ceil(v.x), std::ceil(v.y), std::ceil(v.z)); } +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.9 -> -1.0) + * @param v target vector + */ +static double3 trunc(double3 v) noexcept { return double3(std::trunc(v.x), std::trunc(v.y), std::trunc(v.z)); } + +/*********************************************************************************************************************** + * @brief Returns dot product between two vector. + * + * @param a first vector to dot + * @param b second vector to dot + */ +static constexpr double dot(double3 a, double3 b) noexcept { return a.x * b.x + a.y * b.y + a.z * b.z; } +/** + * @brief Returns cross product between two vector. + * + * @param a first vector to cross + * @param b second vector to cross + */ +static constexpr double3 cross(double3 a, double3 b) noexcept +{ + return double3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); +} + +/** + * @brief Returns squared length of the vector. (length ^ 2) + * @note Faster to compute because we don't calculate square root. + * @param v target vector + */ +static constexpr double lengthSq(double3 v) noexcept { return dot(v, v); } +/** + * @brief Returns length of the vector. + * @param v target vector + */ +static double length(double3 v) noexcept { return std::sqrt(dot(v, v)); } + +/** + * @brief Returns squared distance between two points. (distance ^ 2) + * @note Faster to compute because we don't calculate square root. + * + * @param a first point + * @param b second point + */ +static constexpr double distanceSq(double3 a, double3 b) noexcept { return lengthSq(a - b); } +/** + * @brief Returns distance between two points. + * + * @param a first point + * @param b second point + */ +static double distance(double3 a, double3 b) noexcept { return length(a - b); } +/** + * @brief Returns true if two vectors are close with specified maximum squared distance. (maxDistance ^ 2) + * + * @param a first vector + * @param b second vector + */ +static constexpr bool isClose(double3 a, double3 b, double maxDistSq = 1.0e-12f) noexcept +{ + return distanceSq(a, b) <= maxDistSq; +} + +/** + * @brief Returns normalized vector. (With length of 1.0) + * @param v target vector to normalize + */ +static double3 normalize(double3 v) noexcept { return v * (1.0 / length(v)); } +/** + * @brief Returns true if vector is normalized with specified tolerance. + * + * @param v target vector to check + * @param tolerance floating point precision tolerance + */ +static bool isNormalized(double3 v, double tolerance = 1.0e-6f) noexcept +{ + return std::abs(lengthSq(v) - 1.0) <= tolerance; +} +/** + * @brief Returns true if any vector element is not a number. + * @param v target vector to check + */ +static bool isNan(double3 v) noexcept { return isnan(v.x) || isnan(v.y) || isnan(v.z); } + +/** + * @brief Remaps each component of vector to the 0.0 - 1.0 range. + * @param v target vector + */ +static double3 repeat(double3 v) noexcept { return double3(repeat(v.x), repeat(v.y), repeat(v.z)); } + +/** + * @brief Linearly interpolates each component of the vector between a and b using t. + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + */ +static double3 lerp(double3 a, double3 b, double t) noexcept { return a * (1.0 - t) + b * t; } +/** + * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @note Always use this function instead of basic lerp() when you have variable delta time! + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + * @param dt current delta time + */ +static double3 lerpDelta(double3 a, double3 b, double f, double dt) noexcept +{ + return a + (1.0 - std::pow(f, dt)) * (b - a); +} + +/** + * @brief Computes the power of each component of base b raised to the corresponding exponent e. + * + * @param b target base vector to raise + * @param e exponent vector + */ +static double3 pow(double3 b, double3 e) noexcept +{ + return double3(std::pow(b.x, e.x), std::pow(b.y, e.y), std::pow(b.z, e.z)); +} +/** + * @brief Applies gain function for each component of the vector. + * @note The function is symmetric when x == 0.5. + * + * @param x target vector to gain (0.0 - 1.0) + * @param k gain factor + */ +static double3 gain(double3 x, double3 k) noexcept +{ + auto a = double3(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); + return select(x < 0.5f, a, 1.0 - a); +} + +//********************************************************************************************************************** +static constexpr double4 operator+(double n, double4 v) noexcept { return double4(n) + v; } +static constexpr double4 operator-(double n, double4 v) noexcept { return double4(n) - v; } +static constexpr double4 operator*(double n, double4 v) noexcept { return double4(n) * v; } +static constexpr double4 operator/(double n, double4 v) noexcept { return double4(n) / v; } +static constexpr bool operator==(double n, double4 v) noexcept { return double4(n) == v; } +static constexpr bool operator!=(double n, double4 v) noexcept { return double4(n) != v; } +static constexpr uint4 operator<(double n, double4 v) noexcept { return double4(n) < v; } +static constexpr uint4 operator>(double n, double4 v) noexcept { return double4(n) > v; } +static constexpr uint4 operator<=(double n, double4 v) noexcept { return double4(n) <= v; } +static constexpr uint4 operator>=(double n, double4 v) noexcept { return double4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(double4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint4 equal(double4 a, double4 b) noexcept +{ + return uint4(a.x == b.x ? UINT32_MAX : 0, a.y == b.y ? UINT32_MAX : 0, + a.z == b.z ? UINT32_MAX : 0, a.w == b.w ? UINT32_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static uint4 notEqual(double4 a, double4 b) noexcept +{ + return uint4(a.x != b.x ? UINT32_MAX : 0, a.y != b.y ? UINT32_MAX : 0, + a.z != b.z ? UINT32_MAX : 0, a.w != b.w ? UINT32_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const double4& a, const double4& b) noexcept { return memcmp(&a, &b, sizeof(double4)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr double4 select(uint4 c, double4 t, double4 f) noexcept +{ + return double4(c.x & 0x80000000u ? t.x : f.x, c.y & 0x80000000u ? t.y : f.y, + c.z & 0x80000000u ? t.z : f.z, c.w & 0x80000000u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr double4 min(double4 a, double4 b) noexcept +{ + return double4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr double4 max(double4 a, double4 b) noexcept +{ + return double4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr double4 min(double4 a, double4 b, double4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr double4 max(double4 a, double4 b, double4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. (Inclusive range) + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr double4 clamp(double4 v, double4 min, double4 max) noexcept +{ + return double4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} +/** + * @brief Clamps vector components between the 0.0 and 1.0. (Inclusive range) + * @param v target vector to saturate + */ +static constexpr double4 saturate(double4 v) noexcept +{ + return double4(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0), + std::clamp(v.z, 0.0, 1.0), std::clamp(v.w, 0.0, 1.0)); +} + +/*********************************************************************************************************************** + * @brief Fused multiply add, calculates: mul1 * mul2 + add + * + * @param mul1 first vector multiplier + * @param mul2 second vector multiplier + * @param add vector addend + */ +static double4 fma(double4 mul1, double4 mul2, double4 add) noexcept +{ + return double4(std::fma(mul1.x, mul2.x, add.x), std::fma(mul1.y, mul2.y, add.y), + std::fma(mul1.z, mul2.z, add.z), std::fma(mul1.w, mul2.w, add.w)); +} +/** + * @brief Returns absolute value for each component of the vector. + * @param v target vector + */ +static double4 abs(double4 v) noexcept { return double4(std::abs(v.x), std::abs(v.y), std::abs(v.z), std::abs(v.w)); } +/** + * @brief Returns square root for each component of the vector. + * @param v target vector + */ +static double4 sqrt(double4 v) noexcept +{ + return double4(std::sqrt(v.x), std::sqrt(v.y), std::sqrt(v.z), std::sqrt(v.w)); +} +/** + * @brief Returns sign for each component of the vector. + * @param v target vector + */ +static double4 sign(double4 v) noexcept { return double4(sign(v.x), sign(v.y), sign(v.z), sign(v.w)); } +/** + * @brief Returns sign bits of the vector. (4 bits) + * @param v target vector + */ +static uint32 signBits(double4 v) noexcept +{ + return (std::signbit(v.x) ? 1u : 0u) | (std::signbit(v.y) ? 2u : 0u) | + (std::signbit(v.z) ? 4u : 0u) | (std::signbit(v.w) ? 8u : 0u); +} + +/** + * @brief Rounds each component of the vector to nearest integer. (1.5 -> 2.0; -1.5 -> -2.0) + * @param v target vector + */ +static double4 round(double4 v) noexcept +{ + return double4(std::round(v.x), std::round(v.y), std::round(v.z), std::round(v.w)); +} +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.7 -> -2.0) + * @param v target vector + */ +static double4 floor(double4 v) noexcept +{ + return double4(std::floor(v.x), std::floor(v.y), std::floor(v.z), std::floor(v.w)); +} +/** + * @brief Rounds each component of the vector to nearest integer. (1.4 -> 2.0; -1.4 -> -1.0) + * @param v target vector + */ +static double4 ceil(double4 v) noexcept +{ + return double4(std::ceil(v.x), std::ceil(v.y), std::ceil(v.z), std::ceil(v.w)); +} +/** + * @brief Rounds each component of the vector to nearest integer. (1.7 -> 1.0; -1.9 -> -1.0) + * @param v target vector + */ +static double4 trunc(double4 v) noexcept +{ + return double4(std::trunc(v.x), std::trunc(v.y), std::trunc(v.z), std::trunc(v.w)); +} + +/*********************************************************************************************************************** + * @brief Returns dot product between two vector. + * + * @param a first vector to dot + * @param b second vector to dot + */ +static constexpr double dot(double4 a, double4 b) noexcept { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } + +/** + * @brief Returns squared length of the vector. (length ^ 2) + * @note Faster to compute because we don't calculate square root. + * @param v target vector + */ +static constexpr double lengthSq(double4 v) noexcept { return dot(v, v); } +/** + * @brief Returns length of the vector. + * @param v target vector + */ +static double length(double4 v) noexcept { return std::sqrt(dot(v, v)); } + +/** + * @brief Returns squared distance between two points. (distance ^ 2) + * @note Faster to compute because we don't calculate square root. + * + * @param a first point + * @param b second point + */ +static constexpr double distanceSq(double4 a, double4 b) noexcept { return lengthSq(a - b); } +/** + * @brief Returns distance between two points. + * + * @param a first point + * @param b second point + */ +static double distance(double4 a, double4 b) noexcept { return length(a - b); } +/** + * @brief Returns true if two vectors are close with specified maximum squared distance. (maxDistance ^ 2) + * + * @param a first vector + * @param b second vector + */ +static constexpr bool isClose(double4 a, double4 b, double maxDistSq = 1.0e-12f) noexcept +{ + return distanceSq(a, b) <= maxDistSq; +} + +/** + * @brief Returns normalized vector. (With length of 1.0) + * @param v target vector to normalize + */ +static double4 normalize(double4 v) noexcept { return v * (1.0 / length(v)); } +/** + * @brief Returns true if vector is normalized with specified tolerance. + * + * @param v target vector to check + * @param tolerance floating point precision tolerance + */ +static bool isNormalized(double4 v, double tolerance = 1.0e-6f) noexcept +{ + return std::abs(lengthSq(v) - 1.0) <= tolerance; +} +/** + * @brief Returns true if any vector element is not a number. + * @param v target vector to check + */ +static bool isNan(double4 v) noexcept { return isnan(v.x) || isnan(v.y) || isnan(v.z) || isnan(v.w); } + +/** + * @brief Remaps each component of vector to the 0.0 - 1.0 range. + * @param v target vector + */ +static double4 repeat(double4 v) noexcept { return double4(repeat(v.x), repeat(v.y), repeat(v.z), repeat(v.w)); } + +/** + * @brief Linearly interpolates each component of the vector between a and b using t. + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + */ +static double4 lerp(double4 a, double4 b, double t) noexcept { return a * (1.0 - t) + b * t; } +/** + * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @note Always use this function instead of basic lerp() when you have variable delta time! + * + * @param a minimum vector (t == 0.0) + * @param b maximum vector (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + * @param dt current delta time + */ +static double4 lerpDelta(double4 a, double4 b, double f, double dt) noexcept +{ + return a + (1.0 - std::pow(f, dt)) * (b - a); +} + +/** + * @brief Computes the power of each component of base b raised to the corresponding exponent e. + * + * @param b target base vector to raise + * @param e exponent vector + */ +static double4 pow(double4 b, double4 e) noexcept +{ + return double4(std::pow(b.x, e.x), std::pow(b.y, e.y), std::pow(b.z, e.z), std::pow(b.w, e.w)); +} +/** + * @brief Applies gain function for each component of the vector. + * @note The function is symmetric when x == 0.5. + * + * @param x target vector to gain (0.0 - 1.0) + * @param k gain factor + */ +static double4 gain(double4 x, double4 k) noexcept +{ + auto a = double4(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); + return select(x < 0.5f, a, 1.0 - a); +} + +//********************************************************************************************************************** +// TODO: possibly add more specific math functions like remquo, sph_neumann or dFdx. + +static double2 mod(double2 a, double2 b) noexcept { return double2(std::fmod(a.x, b.x), std::fmod(a.y, b.y)); } +static double2 exp(double2 v) noexcept { return double2(std::exp(v.x), std::exp(v.y)); } +static double2 exp2(double2 v) noexcept { return double2(std::exp2(v.x), std::exp2(v.y)); } +static double2 expm1(double2 v) noexcept { return double2(std::expm1(v.x), std::expm1(v.y)); } +static double2 log(double2 v) noexcept { return double2(std::log(v.x), std::log(v.y)); } +static double2 log10(double2 v) noexcept { return double2(std::log10(v.x), std::log10(v.y)); } +static double2 log2(double2 v) noexcept { return double2(std::log2(v.x), std::log2(v.y)); } +static double2 log1p(double2 v) noexcept { return double2(std::log1p(v.x), std::log1p(v.y)); } +static double2 cbrt(double2 v) noexcept { return double2(std::cbrt(v.x), std::cbrt(v.y)); } +static double2 sin(double2 v) noexcept { return double2(std::sin(v.x), std::sin(v.y)); } +static double2 cos(double2 v) noexcept { return double2(std::cos(v.x), std::cos(v.y)); } +static double2 tan(double2 v) noexcept { return double2(std::tan(v.x), std::tan(v.y)); } +static double2 asin(double2 v) noexcept { return double2(std::asin(v.x), std::asin(v.y)); } +static double2 acos(double2 v) noexcept { return double2(std::acos(v.x), std::acos(v.y)); } +static double2 atan(double2 v) noexcept { return double2(std::atan(v.x), std::atan(v.y)); } +static double2 atan(double2 a, double2 b) noexcept { return double2(std::atan2(a.x, b.x), std::atan2(a.y, b.y)); } +static double2 sinh(double2 v) noexcept { return double2(std::sinh(v.x), std::sinh(v.y)); } +static double2 cosh(double2 v) noexcept { return double2(std::cosh(v.x), std::cosh(v.y)); } +static double2 tanh(double2 v) noexcept { return double2(std::tanh(v.x), std::tanh(v.y)); } +static double2 asinh(double2 v) noexcept { return double2(std::asinh(v.x), std::asinh(v.y)); } +static double2 acosh(double2 v) noexcept { return double2(std::acosh(v.x), std::acosh(v.y)); } +static double2 atanh(double2 v) noexcept { return double2(std::atanh(v.x), std::atanh(v.y)); } + +//********************************************************************************************************************** +static double3 mod(double3 a, double3 b) noexcept +{ + return double3(std::fmod(a.x, b.x), std::fmod(a.y, b.y), std::fmod(a.z, b.z)); +} +static double3 exp(double3 v) noexcept { return double3(std::exp(v.x), std::exp(v.y), std::exp(v.z)); } +static double3 exp2(double3 v) noexcept { return double3(std::exp2(v.x), std::exp2(v.y), std::exp2(v.z)); } +static double3 expm1(double3 v) noexcept { return double3(std::expm1(v.x), std::expm1(v.y), std::expm1(v.z)); } +static double3 log(double3 v) noexcept { return double3(std::log(v.x), std::log(v.y), std::log(v.z)); } +static double3 log10(double3 v) noexcept { return double3(std::log10(v.x), std::log10(v.y), std::log10(v.z)); } +static double3 log2(double3 v) noexcept { return double3(std::log2(v.x), std::log2(v.y), std::log2(v.z)); } +static double3 log1p(double3 v) noexcept { return double3(std::log1p(v.x), std::log1p(v.y), std::log1p(v.z)); } +static double3 cbrt(double3 v) noexcept { return double3(std::cbrt(v.x), std::cbrt(v.y), std::cbrt(v.z)); } +static double3 sin(double3 v) noexcept { return double3(std::sin(v.x), std::sin(v.y), std::sin(v.z)); } +static double3 cos(double3 v) noexcept { return double3(std::cos(v.x), std::cos(v.y), std::cos(v.z)); } +static double3 tan(double3 v) noexcept { return double3(std::tan(v.x), std::tan(v.y), std::tan(v.z)); } +static double3 asin(double3 v) noexcept { return double3(std::asin(v.x), std::asin(v.y), std::asin(v.z)); } +static double3 acos(double3 v) noexcept { return double3(std::acos(v.x), std::acos(v.y), std::acos(v.z)); } +static double3 atan(double3 v) noexcept { return double3(std::atan(v.x), std::atan(v.y), std::atan(v.z)); } +static double3 atan(double3 a, double3 b) noexcept +{ + return double3(std::atan2(a.x, b.x), std::atan2(a.y, b.y), std::atan2(a.z, b.z)); +} +static double3 sinh(double3 v) noexcept { return double3(std::sinh(v.x), std::sinh(v.y), std::sinh(v.z)); } +static double3 cosh(double3 v) noexcept { return double3(std::cosh(v.x), std::cosh(v.y), std::cosh(v.z)); } +static double3 tanh(double3 v) noexcept { return double3(std::tanh(v.x), std::tanh(v.y), std::tanh(v.z)); } +static double3 asinh(double3 v) noexcept { return double3(std::asinh(v.x), std::asinh(v.y), std::asinh(v.z)); } +static double3 acosh(double3 v) noexcept { return double3(std::acosh(v.x), std::acosh(v.y), std::acosh(v.z)); } +static double3 atanh(double3 v) noexcept { return double3(std::atanh(v.x), std::atanh(v.y), std::atanh(v.z)); } + +//********************************************************************************************************************** +static double4 mod(double4 a, double4 b) noexcept +{ + return double4(std::fmod(a.x, b.x), std::fmod(a.y, b.y), std::fmod(a.z, b.z), std::fmod(a.w, b.w)); +} +static double4 exp(double4 v) noexcept +{ + return double4(std::exp(v.x), std::exp(v.y), std::exp(v.z), std::exp(v.w)); +} +static double4 exp2(double4 v) noexcept +{ + return double4(std::exp2(v.x), std::exp2(v.y), std::exp2(v.z), std::exp2(v.w)); +} +static double4 expm1(double4 v) noexcept +{ + return double4(std::expm1(v.x), std::expm1(v.y), std::expm1(v.z), std::expm1(v.w)); +} +static double4 log(double4 v) noexcept +{ + return double4(std::log(v.x), std::log(v.y), std::log(v.z), std::log(v.w)); +} +static double4 log10(double4 v) noexcept +{ + return double4(std::log10(v.x), std::log10(v.y), std::log10(v.z), std::log10(v.w)); +} +static double4 log2(double4 v) noexcept +{ + return double4(std::log2(v.x), std::log2(v.y), std::log2(v.z), std::log2(v.w)); +} +static double4 log1p(double4 v) noexcept +{ + return double4(std::log1p(v.x), std::log1p(v.y), std::log1p(v.z), std::log1p(v.w)); +} +static double4 cbrt(double4 v) noexcept +{ + return double4(std::cbrt(v.x), std::cbrt(v.y), std::cbrt(v.z), std::cbrt(v.w)); +} +static double4 sin(double4 v) noexcept +{ + return double4(std::sin(v.x), std::sin(v.y), std::sin(v.z), std::sin(v.w)); +} +static double4 cos(double4 v) noexcept +{ + return double4(std::cos(v.x), std::cos(v.y), std::cos(v.z), std::cos(v.w)); +} +static double4 tan(double4 v) noexcept +{ + return double4(std::tan(v.x), std::tan(v.y), std::tan(v.z), std::tan(v.w)); +} +static double4 asin(double4 v) noexcept +{ + return double4(std::asin(v.x), std::asin(v.y), std::asin(v.z), std::asin(v.w)); +} +static double4 acos(double4 v) noexcept +{ + return double4(std::acos(v.x), std::acos(v.y), std::acos(v.z), std::acos(v.w)); +} +static double4 atan(double4 v) noexcept +{ + return double4(std::atan(v.x), std::atan(v.y), std::atan(v.z), std::atan(v.w)); +} +static double4 atan(double4 a, double4 b) noexcept +{ + return double4(std::atan2(a.x, b.x), std::atan2(a.y, b.y), std::atan2(a.z, b.z), std::atan2(a.w, b.w)); +} +static double4 sinh(double4 v) noexcept +{ + return double4(std::sinh(v.x), std::sinh(v.y), std::sinh(v.z), std::sinh(v.w)); +} +static double4 cosh(double4 v) noexcept +{ + return double4(std::cosh(v.x), std::cosh(v.y), std::cosh(v.z), std::cosh(v.w)); +} +static double4 tanh(double4 v) noexcept +{ + return double4(std::tanh(v.x), std::tanh(v.y), std::tanh(v.z), std::tanh(v.w)); +} +static double4 asinh(double4 v) noexcept +{ + return double4(std::asinh(v.x), std::asinh(v.y), std::asinh(v.z), std::asinh(v.w)); +} +static double4 acosh(double4 v) noexcept +{ + return double4(std::acosh(v.x), std::acosh(v.y), std::acosh(v.z), std::acosh(v.w)); +} +static double4 atanh(double4 v) noexcept +{ + return double4(std::atanh(v.x), std::atanh(v.y), std::atanh(v.z), std::atanh(v.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/float.hpp b/include/math/vector/float.hpp index 39de9cf..7a33615 100644 --- a/include/math/vector/float.hpp +++ b/include/math/vector/float.hpp @@ -14,20 +14,19 @@ /*********************************************************************************************************************** * @file - * @brief Common floating point vector functions. + * @brief Common floating point 32 bit vector functions. * @details Based on this project: https://github.com/g-truc/glm */ #pragma once #include "math/common.hpp" -#include "math/vector/int.hpp" -#include +#include "math/vector/half.hpp" namespace math { /** - * @brief Floating point 2 component vector structure. + * @brief A 2-component vector of 32-bit floating-point values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] float2 @@ -36,27 +35,62 @@ struct [[nodiscard]] float2 float y; /**< Second vector component. */ /** - * @brief Creates a new floating point 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit floating-point values. * @param xy target value for all vector components */ constexpr explicit float2(float xy = 0.0f) noexcept : x(xy), y(xy) { } /** - * @brief Creates a new floating point 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit floating-point values. * * @param x first vector component value * @param y second vector component value */ constexpr float2(float x, float y) noexcept : x(x), y(y) { } /** - * @brief Creates a new floating point 2 component vector structure. - * @param xy target unsigned integer vector value + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value */ - constexpr float2(uint2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + explicit constexpr float2(half2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } /** - * @brief Creates a new floating point 2 component vector structure. - * @param xy target signed integer vector value + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value */ - constexpr float2(int2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + explicit constexpr float2(long2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr float2(ulong2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr float2(int2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr float2(uint2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr float2(short2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr float2(ushort2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr float2(sbyte2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr float2(byte2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -77,26 +111,15 @@ struct [[nodiscard]] float2 return ((float*)this)[i]; } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ - constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns as 2 component signed integer vector. (xy) - */ + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } - /** - * @brief Returns first vector component as unsigned integer. (x) - */ - constexpr explicit operator uint32() const noexcept { return (uint32)x; } - /** - * @brief Returns first vector component as signed integer. (x) - */ - constexpr explicit operator int32() const noexcept { return (int32)x; } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator float() const noexcept { return x; } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr float2 operator+(float2 v) const noexcept { return float2(x + v.x, y + v.y); } @@ -163,7 +186,7 @@ inline constexpr float2 float2::bottom = float2(0.0f, -1.0f); inline constexpr float2 float2::top = float2(0.0f, 1.0f); /*********************************************************************************************************************** - * @brief Floating point 3 component vector structure. + * @brief A 3-component vector of 32-bit floating-point values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] float3 @@ -173,12 +196,12 @@ struct [[nodiscard]] float3 float z; /**< Third vector component. */ /** - * @brief Creates a new floating point 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit floating-point values. * @param xyz target value for all vector components */ constexpr explicit float3(float xyz = 0.0f) noexcept : x(xyz), y(xyz), z(xyz) { } /** - * @brief Creates a new floating point 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit floating-point values. * * @param x first vector component value * @param y second vector component value @@ -186,29 +209,64 @@ struct [[nodiscard]] float3 */ constexpr float3(float x, float y, float z) noexcept : x(x), y(y), z(z) { } /** - * @brief Creates a new floating point 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit floating-point values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value */ constexpr float3(float2 xy, float z) noexcept : x(xy.x), y(xy.y), z(z) { } /** - * @brief Creates a new floating point 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit floating-point values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value */ constexpr float3(float x, float2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } /** - * @brief Creates a new floating point 3 component vector structure. - * @param xyz target unsigned integer vector value + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr float3(half3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr float3(long3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr float3(ulong3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr float3(int3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr float3(uint3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr float3(short3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr float3(ushort3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value */ - constexpr float3(uint3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(sbyte3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } /** - * @brief Creates a new floating point 3 component vector structure. - * @param xyz target signed integer vector value + * @brief Creates a new 3-component vector of 32-bit floating-point values. + * @param xyz first, second and third vector component value */ - constexpr float3(int3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(byte3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -229,38 +287,25 @@ struct [[nodiscard]] float3 return ((float*)this)[i]; } - /** - * @brief Returns as 3 component signed integer vector. (xyz) - */ + constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } - /** - * @brief Returns as 3 component unsigned integer vector. (xyz) - */ constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } - /** - * @brief Returns as 2 component signed integer vector. (xy) - */ + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator float2() const noexcept { return float2(x, y); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns first vector component as unsigned integer. (x) - */ - constexpr explicit operator uint32() const noexcept { return (uint32)x; } - /** - * @brief Returns first vector component as signed integer. (x) - */ - constexpr explicit operator int32() const noexcept { return (int32)x; } - /** - * @brief Returns as 2 component floating point vector. (xy) - */ - constexpr explicit operator float2() const noexcept { return float2(x, y); } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator float() const noexcept { return x; } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr float3 operator+(float3 v) const noexcept { return float3(x + v.x, y + v.y, z + v.z); } @@ -329,7 +374,7 @@ inline constexpr float3 float3::back = float3(0.0f, 0.0f, -1.0f); inline constexpr float3 float3::front = float3(0.0f, 0.0f, 1.0f); /*********************************************************************************************************************** - * @brief Floating point 4 component vector structure. + * @brief A 4-component vector of 32-bit floating-point values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] float4 @@ -340,12 +385,12 @@ struct [[nodiscard]] float4 float w; /**< Fourth vector component. */ /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * @param xyzw target value for all vector components */ constexpr explicit float4(float xyzw = 0.0f) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * * @param x first vector component value * @param y second vector component value @@ -354,62 +399,95 @@ struct [[nodiscard]] float4 */ constexpr float4(float x, float y, float z, float w) noexcept : x(x), y(y), z(z), w(w) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value * @param w fourth vector component value */ constexpr float4(float2 xy, float z, float w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value * @param w fourth vector component value */ constexpr float4(float x, float2 yz, float w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * * @param x first vector component value * @param y second vector component value - * @param zw third and fourth vector components value + * @param zw third and fourth vector component value */ constexpr float4(float x, float y, float2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * - * @param xy first and second vector components value - * @param zw third and fourth vector components value + * @param xy first and second vector component value + * @param zw third and fourth vector component value */ constexpr float4(float2 xy, float2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * - * @param xyz first, second and third vector components value + * @param xyz first, second and third vector component value * @param w fourth vector component value */ constexpr float4(float3 xyz, float w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } /** - * @brief Creates a new floating point 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit floating-point values. * * @param x first vector component value - * @param yzw second, third and fourth vector components value + * @param yzw second, third and fourth vector component value */ constexpr float4(float x, float3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } /** - * @brief Creates a new floating point 4 component vector structure. - * @param xyzw target unsigned integer vector value + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr float4(half4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr float4(long4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value */ - constexpr float4(uint4 xyzw) noexcept : - x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + explicit constexpr float4(ulong4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } /** - * @brief Creates a new floating point 4 component vector structure. - * @param xyzw target signed integer vector value + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value */ - constexpr float4(int4 xyzw) noexcept : - x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + explicit constexpr float4(int4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr float4(uint4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr float4(short4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr float4(ushort4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr float4(sbyte4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr float4(byte4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -430,50 +508,35 @@ struct [[nodiscard]] float4 return ((float*)this)[i]; } - /** - * @brief Returns as 4 component signed integer vector. (xyzw) - */ + constexpr explicit operator half4() const noexcept { return half4((half)x, (half)y, (half)z, (half)w); } + constexpr explicit operator long4() const noexcept { return long4((int64)x, (int64)y, (int64)z, (int64)w); } + constexpr explicit operator ulong4() const noexcept { return ulong4((uint64)x, (uint64)y, (uint64)z, (uint64)w); } constexpr explicit operator int4() const noexcept { return int4((int32)x, (int32)y, (int32)z, (int32)w); } - /** - * @brief Returns as 4 component unsigned integer vector. (xyzw) - */ constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } - /** - * @brief Returns as 3 component signed integer vector. (xyz) - */ + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator float3() const noexcept { return float3(x, y, z); } + constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } - /** - * @brief Returns as 3 component unsigned integer vector. (xyz) - */ constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } - /** - * @brief Returns as 2 component signed integer vector. (xy) - */ + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator float2() const noexcept { return float2(x, y); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns first vector component as unsigned integer. (x) - */ - constexpr explicit operator uint32() const noexcept { return (uint32)x; } - /** - * @brief Returns first vector component as signed integer. (x) - */ - constexpr explicit operator int32() const noexcept { return (int32)x; } - /** - * @brief Returns as 3 component floating point vector. (xyz) - */ - constexpr explicit operator float3() const noexcept { return float3(x, y, z); } - /** - * @brief Returns as 2 component floating point vector. (xy) - */ - constexpr explicit operator float2() const noexcept { return float2(x, y); } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator float() const noexcept { return x; } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr float4 operator+(float4 v) const noexcept { return float4(x + v.x, y + v.y, z + v.z, w + v.w); } diff --git a/include/math/vector/half.hpp b/include/math/vector/half.hpp new file mode 100644 index 0000000..54b25e7 --- /dev/null +++ b/include/math/vector/half.hpp @@ -0,0 +1,447 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common floating point 16 bit vector functions. + */ + +// TODO: add common math functions after targeting AVX-512 or AVX10 instruction set. + +#pragma once +#include "math/vector/long.hpp" + +namespace math +{ + +/** + * @brief A 2-component vector of 16-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] half2 +{ + half x; /**< First vector component. */ + half y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy target value for all vector components + */ + constexpr explicit half2(half xy = 0.0f) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr half2(half x, half y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(long2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(ulong2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(int2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(uint2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(short2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + explicit constexpr half2(ushort2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr half2(sbyte2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit floating-point values. + * @param xy first and second vector component value + */ + constexpr half2(byte2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + half& operator[](psize i) noexcept + { + assert(i <= 1); + return ((half*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + half operator[](psize i) const noexcept + { + assert(i <= 1); + return ((half*)this)[i]; + } + + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + static const half2 zero, one, minusOne, min, minusMin, max, minusMax, + epsilon, inf, minusInf, nan, left, right, bottom, top; +}; + +inline constexpr half2 half2::zero = half2(0.0f); +inline constexpr half2 half2::one = half2(1.0f); +inline constexpr half2 half2::minusOne = half2(-1.0f); +inline constexpr half2 half2::min = half2(FLT16_MIN); +inline constexpr half2 half2::minusMin = half2(-FLT16_MIN); +inline constexpr half2 half2::max = half2(FLT16_MAX); +inline constexpr half2 half2::minusMax = half2(-FLT16_MAX); +inline constexpr half2 half2::epsilon = half2(FLT16_EPSILON); +inline constexpr half2 half2::inf = half2(INFINITY); +inline constexpr half2 half2::minusInf = half2(-INFINITY); +inline constexpr half2 half2::nan = half2(NAN); +inline constexpr half2 half2::left = half2(-1.0f, 0.0f); +inline constexpr half2 half2::right = half2(1.0f, 0.0f); +inline constexpr half2 half2::bottom = half2(0.0f, -1.0f); +inline constexpr half2 half2::top = half2(0.0f, 1.0f); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 16-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] half3 +{ + half x; /**< First vector component. */ + half y; /**< Second vector component. */ + half z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz target value for all vector components + */ + constexpr explicit half3(half xyz = 0.0f) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr half3(half x, half y, half z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr half3(half2 xy, half z) noexcept : x(xy.x), y(xy.y), z(z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr half3(half x, half2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(long3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(ulong3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(int3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(uint3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(short3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + explicit constexpr half3(ushort3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr half3(sbyte3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit floating-point values. + * @param xyz first, second and third vector component value + */ + constexpr half3(byte3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + half& operator[](psize i) noexcept + { + assert(i <= 2); + return ((half*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + half operator[](psize i) const noexcept + { + assert(i <= 2); + return ((half*)this)[i]; + } + + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + static const half3 zero, one, minusOne, min, minusMin, max, minusMax, + epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; +}; + +inline constexpr half3 half3::zero = half3(0.0f); +inline constexpr half3 half3::one = half3(1.0f); +inline constexpr half3 half3::minusOne = half3(-1.0f); +inline constexpr half3 half3::min = half3(FLT16_MIN); +inline constexpr half3 half3::minusMin = half3(-FLT16_MIN); +inline constexpr half3 half3::max = half3(FLT16_MAX); +inline constexpr half3 half3::minusMax = half3(-FLT16_MAX); +inline constexpr half3 half3::epsilon = half3(FLT16_EPSILON); +inline constexpr half3 half3::inf = half3(INFINITY); +inline constexpr half3 half3::minusInf = half3(-INFINITY); +inline constexpr half3 half3::nan = half3(NAN); +inline constexpr half3 half3::left = half3(-1.0f, 0.0f, 0.0f); +inline constexpr half3 half3::right = half3(1.0f, 0.0f, 0.0f); +inline constexpr half3 half3::bottom = half3(0.0f, -1.0f, 0.0f); +inline constexpr half3 half3::top = half3(0.0f, 1.0f, 0.0f); +inline constexpr half3 half3::back = half3(0.0f, 0.0f, -1.0f); +inline constexpr half3 half3::front = half3(0.0f, 0.0f, 1.0f); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 16-bit floating-point values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] half4 +{ + half x; /**< First vector component. */ + half y; /**< Second vector component. */ + half z; /**< Third vector component. */ + half w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw target value for all vector components + */ + constexpr explicit half4(half xyzw = 0.0f) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr half4(half x, half y, half z, half w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr half4(half2 xy, half z, half w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr half4(half x, half2 yz, half w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr half4(half x, half y, half2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr half4(half2 xy, half2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr half4(half3 xyz, half w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * + * @param x first vector component value + * @param yzw second, third and fourth vector component value + */ + constexpr half4(half x, half3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(long4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(ulong4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(int4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(uint4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(short4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + explicit constexpr half4(ushort4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr half4(sbyte4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit floating-point values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr half4(byte4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + half& operator[](psize i) noexcept + { + assert(i <= 3); + return ((half*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + half operator[](psize i) const noexcept + { + assert(i <= 3); + return ((half*)this)[i]; + } + + constexpr explicit operator long4() const noexcept { return long4((int64)x, (int64)y, (int64)z, (int64)w); } + constexpr explicit operator ulong4() const noexcept { return ulong4((uint64)x, (uint64)y, (uint64)z, (uint64)w); } + constexpr explicit operator int4() const noexcept { return int4((int32)x, (int32)y, (int32)z, (int32)w); } + constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } + constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } + constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + static const half4 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan; +}; + +inline constexpr half4 half4::zero = half4(0.0f); +inline constexpr half4 half4::one = half4(1.0f); +inline constexpr half4 half4::minusOne = half4(-1.0f); +inline constexpr half4 half4::min = half4(FLT16_MIN); +inline constexpr half4 half4::minusMin = half4(-FLT16_MIN); +inline constexpr half4 half4::max = half4(FLT16_MAX); +inline constexpr half4 half4::minusMax = half4(-FLT16_MAX); +inline constexpr half4 half4::epsilon = half4(FLT16_EPSILON); +inline constexpr half4 half4::inf = half4(INFINITY); +inline constexpr half4 half4::minusInf = half4(-INFINITY); +inline constexpr half4 half4::nan = half4(NAN); + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/int.hpp b/include/math/vector/int.hpp index ef9a785..70fc2a9 100644 --- a/include/math/vector/int.hpp +++ b/include/math/vector/int.hpp @@ -14,18 +14,19 @@ /*********************************************************************************************************************** * @file - * @brief Common signed integer vector functions. + * @brief Common signed integer 32 bit vector functions. * @details Based on this project: https://github.com/g-truc/glm */ #pragma once +#include "math/vector/short.hpp" #include "math/vector/uint.hpp" namespace math { /** - * @brief Signed integer 2 component vector structure. + * @brief A 2-component vector of 32-bit signed integer values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] int2 @@ -34,22 +35,42 @@ struct [[nodiscard]] int2 int32 y; /**< Second vector component. */ /** - * @brief Creates a new signed integer 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit signed integer values. * @param xy target value for all vector components */ constexpr explicit int2(int32 xy = 0) noexcept : x(xy), y(xy) { } /** - * @brief Creates a new signed integer 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit signed integer values. * * @param x first vector component value * @param y second vector component value */ constexpr int2(int32 x, int32 y) noexcept : x(x), y(y) { } /** - * @brief Creates a new signed integer 2 component vector structure. - * @param xy target unsigned integer vector value + * @brief Creates a new 2-component vector of 32-bit signed integer values. + * @param xy first and second vector component value */ constexpr int2(uint2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr int2(short2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr int2(ushort2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr int2(sbyte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + /** + * @brief Creates a new 2-component vector of 32-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr int2(byte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -70,18 +91,11 @@ struct [[nodiscard]] int2 return ((int32*)this)[i]; } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns first vector component as unsigned integer value. (x) - */ - constexpr explicit operator uint32() noexcept { return (uint32)x; } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator int32() noexcept { return x; } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr int2 operator+(int2 v) const noexcept { return int2(x + v.x, y + v.y); } @@ -153,19 +167,21 @@ struct [[nodiscard]] int2 constexpr uint2 operator<=(int32 n) const noexcept { return *this <= int2(n); } constexpr uint2 operator>=(int32 n) const noexcept { return *this >= int2(n); } - static const int2 zero, one, minusOne, left, right, bottom, top; + static const int2 zero, one, minusOne, min, max, left, right, bottom, top; }; inline const int2 int2::zero = int2(0); inline const int2 int2::one = int2(1); inline const int2 int2::minusOne = int2(-1); +inline const int2 int2::min = int2(INT32_MIN); +inline const int2 int2::max = int2(INT32_MAX); inline const int2 int2::left = int2(-1, 0); inline const int2 int2::right = int2(1, 0); inline const int2 int2::bottom = int2(0, -1); inline const int2 int2::top = int2(0, 1); /*********************************************************************************************************************** - * @brief Signed integer 3 component vector structure. + * @brief A 3-component vector of 32-bit signed integer values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] int3 @@ -175,12 +191,12 @@ struct [[nodiscard]] int3 int32 z; /**< Third vector component. */ /** - * @brief Creates a new signed integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit signed integer values. * @param xyz target value for all vector components */ constexpr explicit int3(int32 xyz = 0) noexcept : x(xyz), y(xyz), z(xyz) { } /** - * @brief Creates a new signed integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit signed integer values. * * @param x first vector component value * @param y second vector component value @@ -188,24 +204,44 @@ struct [[nodiscard]] int3 */ constexpr int3(int32 x, int32 y, int32 z) noexcept : x(x), y(y), z(z) { } /** - * @brief Creates a new signed integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit signed integer values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value */ constexpr int3(int2 xy, int32 z) noexcept : x(xy.x), y(xy.y), z(x) { } /** - * @brief Creates a new signed integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit signed integer values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value */ constexpr int3(int32 x, int2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } /** - * @brief Creates a new signed integer 3 component vector structure. - * @param xyz target unsigned integer vector value + * @brief Creates a new 3-component vector of 32-bit signed integer values. + * @param xyz first, second and third vector component value */ constexpr int3(uint3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr int3(short3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr int3(ushort3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr int3(sbyte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 32-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr int3(byte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -226,26 +262,17 @@ struct [[nodiscard]] int3 return ((int32*)this)[i]; } - /** - * @brief Returns as 3 component unsigned integer vector. (xyz) - */ constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ - constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns as 2 component signed integer vector. (xy) - */ + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator int2() const noexcept { return int2(x, y); } - /** - * @brief Returns first vector component as unsigned integer value. (xy) - */ - constexpr explicit operator uint32() const noexcept { return (uint32)x; } - /** - * @brief Returns first vector component value. (xy) - */ - constexpr explicit operator int32() const noexcept { return x; } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr int3 operator+(int3 v) const noexcept { return int3(x + v.x, y + v.y, z + v.z); } @@ -317,12 +344,14 @@ struct [[nodiscard]] int3 constexpr uint3 operator<=(int32 n) const noexcept { return *this <= int3(n); } constexpr uint3 operator>=(int32 n) const noexcept { return *this >= int3(n); } - static const int3 zero, one, minusOne, left, right, bottom, top, back, front; + static const int3 zero, one, minusOne, min, max, left, right, bottom, top, back, front; }; inline const int3 int3::zero = int3(0); inline const int3 int3::one = int3(1); inline const int3 int3::minusOne = int3(-1); +inline const int3 int3::min = int3(INT32_MIN); +inline const int3 int3::max = int3(INT32_MAX); inline const int3 int3::left = int3(-1, 0, 0); inline const int3 int3::right = int3(1, 0, 0); inline const int3 int3::bottom = int3(0, -1, 0); @@ -331,7 +360,7 @@ inline const int3 int3::back = int3(0, 0, -1); inline const int3 int3::front = int3(0, 0, 1); /*********************************************************************************************************************** - * @brief Signed integer 4 component vector structure. + * @brief A 4-component vector of 32-bit signed integer values. * @details Commonly used to represent: points, positions, directions, velocities, etc. */ struct [[nodiscard]] int4 @@ -342,12 +371,12 @@ struct [[nodiscard]] int4 int32 w; /**< Fourth vector component. */ /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * @param xyzw target value for all vector components */ constexpr explicit int4(int32 xyzw = 0) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * * @param x first vector component value * @param y second vector component value @@ -356,56 +385,75 @@ struct [[nodiscard]] int4 */ constexpr int4(int32 x, int32 y, int32 z, int32 w) noexcept : x(x), y(y), z(z), w(w) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value * @param w fourth vector component value */ constexpr int4(int2 xy, int32 z, int32 w) noexcept: x(xy.x), y(xy.y), z(z), w(w) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value * @param w fourth vector component value */ constexpr int4(int32 x, int2 yz, int32 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * * @param x first vector component value * @param y second vector component value - * @param zw third and fourth vector components value + * @param zw third and fourth vector component value */ constexpr int4(int32 x, int32 y, int2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * - * @param xy first and second vector components value - * @param zw third and fourth vector components value + * @param xy first and second vector component value + * @param zw third and fourth vector component value */ constexpr int4(int2 xy, int2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * - * @param xyz first, second and third vector components value + * @param xyz first, second and third vector component value * @param w fourth vector component value */ constexpr int4(int3 xyz, int32 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } /** - * @brief Creates a new signed integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit signed integer values. * * @param x first vector component value - * @param[in] yzw second, third and fourth vector components value + * @param[in] yzw second, third and fourth vector component value */ constexpr int4(int32 x, int3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } /** - * @brief Creates a new signed integer 4 component vector structure. - * @param xyzw target unsigned integer vector value + * @brief Creates a new 4-component vector of 32-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr int4(uint4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr int4(short4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value */ - constexpr int4(uint4 xyzw) noexcept : - x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } + constexpr int4(ushort4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr int4(sbyte4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 32-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr int4(byte4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } /******************************************************************************************************************* * @brief Returns vector component by index. @@ -426,34 +474,23 @@ struct [[nodiscard]] int4 return ((int32*)this)[i]; } - /** - * @brief Returns as 4 component unsigned integer vector. (xyzw) - */ constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } - /** - * @brief Returns as 3 component unsigned integer vector. (xyz) - */ - constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } - /** - * @brief Returns as 3 component signed integer vector. (xyz) - */ + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } constexpr explicit operator int3() const noexcept { return int3(x, y, z); } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ - constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } - /** - * @brief Returns as 2 component signed integer vector. (xy) - */ + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator int2() const noexcept { return int2(x, y); } - /** - * @brief Returns first vector component as unsigned integer value. (x) - */ - constexpr explicit operator uint32() const noexcept { return (uint32)x; } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator int32() const noexcept { return x; } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr int4 operator+(int4 v) const noexcept { return int4(x + v.x, y + v.y, z + v.z, w + v.w); } @@ -529,12 +566,14 @@ struct [[nodiscard]] int4 constexpr uint4 operator<=(int32 n) const noexcept { return *this <= int4(n); } constexpr uint4 operator>=(int32 n) const noexcept { return *this >= int4(n); } - static const int4 zero, one, minusOne; + static const int4 zero, one, minusOne, min, max; }; inline const int4 int4::zero = int4(0); inline const int4 int4::one = int4(1); inline const int4 int4::minusOne = int4(-1); +inline const int4 int4::min = int4(INT32_MIN); +inline const int4 int4::max = int4(INT32_MAX); //********************************************************************************************************************** static constexpr int2 operator+(int32 n, int2 v) noexcept { return int2(n) + v; } diff --git a/include/math/vector/long.hpp b/include/math/vector/long.hpp new file mode 100644 index 0000000..32e490b --- /dev/null +++ b/include/math/vector/long.hpp @@ -0,0 +1,964 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common signed integer 64 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/vector/int.hpp" +#include "math/vector/ulong.hpp" + +namespace math +{ + +/** + * @brief A 2-component vector of 64-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] long2 +{ + int64 x; /**< First vector component. */ + int64 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy target value for all vector components + */ + constexpr explicit long2(int64 xy = 0) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr long2(int64 x, int64 y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(ulong2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(int2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(uint2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(short2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(ushort2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(sbyte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + /** + * @brief Creates a new 2-component vector of 64-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr long2(byte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int64& operator[](psize i) noexcept + { + assert(i <= 1); + return ((int64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int64 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((int64*)this)[i]; + } + + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr long2 operator+(long2 v) const noexcept { return long2(x + v.x, y + v.y); } + constexpr long2 operator-(long2 v) const noexcept { return long2(x - v.x, y - v.y); } + constexpr long2 operator*(long2 v) const noexcept { return long2(x * v.x, y * v.y); } + constexpr long2 operator/(long2 v) const noexcept { return long2(x / v.x, y / v.y); } + constexpr long2 operator%(long2 v) const noexcept { return long2(x % v.x, y % v.y); } + constexpr long2 operator&(long2 v) const noexcept { return long2(x & v.x, y & v.y); } + constexpr long2 operator|(long2 v) const noexcept { return long2(x | v.x, y | v.y); } + constexpr long2 operator^(long2 v) const noexcept { return long2(x ^ v.x, y ^ v.y); } + constexpr long2 operator>>(long2 v) const noexcept { return long2(x >> v.x, y >> v.y); } + constexpr long2 operator<<(long2 v) const noexcept { return long2(x << v.x, y << v.y); } + constexpr long2 operator+(int64 n) const noexcept { return long2(x + n, y + n); } + constexpr long2 operator-(int64 n) const noexcept { return long2(x - n, y - n); } + constexpr long2 operator*(int64 n) const noexcept { return long2(x * n, y * n); } + constexpr long2 operator/(int64 n) const noexcept { return long2(x / n, y / n); } + constexpr long2 operator%(int64 n) const noexcept { return long2(x % n, y % n); } + constexpr long2 operator&(int64 n) const noexcept { return long2(x & n, y & n); } + constexpr long2 operator|(int64 n) const noexcept { return long2(x | n, y | n); } + constexpr long2 operator^(int64 n) const noexcept { return long2(x ^ n, y ^ n); } + constexpr long2 operator>>(int64 n) const noexcept { return long2(x >> n, y >> n); } + constexpr long2 operator<<(int64 n) const noexcept { return long2(x << n, y << n); } + constexpr long2 operator-() const noexcept { return long2(-x, -y); } + constexpr long2 operator!() const noexcept { return long2(!x, !y); } + constexpr long2 operator~() const noexcept { return long2(~x, ~y); } + long2& operator+=(long2 v) noexcept { x += v.x; y += v.y; return *this; } + long2& operator-=(long2 v) noexcept { x -= v.x; y -= v.y; return *this; } + long2& operator*=(long2 v) noexcept { x *= v.x; y *= v.y; return *this; } + long2& operator/=(long2 v) noexcept { x /= v.x; y /= v.y; return *this; } + long2& operator%=(long2 v) noexcept { x %= v.x; y %= v.y; return *this; } + long2& operator&=(long2 v) noexcept { x &= v.x; y &= v.y; return *this; } + long2& operator|=(long2 v) noexcept { x |= v.x; y |= v.y; return *this; } + long2& operator^=(long2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + long2& operator>>=(long2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + long2& operator<<=(long2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + long2& operator+=(int64 n) noexcept { x += n; y += n; return *this; } + long2& operator-=(int64 n) noexcept { x -= n; y -= n; return *this; } + long2& operator*=(int64 n) noexcept { x *= n; y *= n; return *this; } + long2& operator/=(int64 n) noexcept { x /= n; y /= n; return *this; } + long2& operator%=(int64 n) noexcept { x %= n; y %= n; return *this; } + long2& operator&=(int64 n) noexcept { x &= n; y &= n; return *this; } + long2& operator|=(int64 n) noexcept { x |= n; y |= n; return *this; } + long2& operator^=(int64 n) noexcept { x ^= n; y ^= n; return *this; } + long2& operator>>=(int64 n) noexcept { x >>= n; y >>= n; return *this; } + long2& operator<<=(int64 n) noexcept { x <<= n; y <<= n; return *this; } + long2& operator=(int64 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(long2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(long2 v) const noexcept { return x != v.x || y != v.y; } + constexpr ulong2 operator<(long2 v) const noexcept + { + return ulong2(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator>(long2 v) const noexcept + { + return ulong2(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator<=(long2 v) const noexcept + { + return ulong2(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator>=(long2 v) const noexcept + { + return ulong2(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0); + } + constexpr bool operator==(int64 n) const noexcept { return *this == long2(n); } + constexpr bool operator!=(int64 n) const noexcept { return *this != long2(n); } + constexpr ulong2 operator<(int64 n) const noexcept { return *this < long2(n); } + constexpr ulong2 operator>(int64 n) const noexcept { return *this > long2(n); } + constexpr ulong2 operator<=(int64 n) const noexcept { return *this <= long2(n); } + constexpr ulong2 operator>=(int64 n) const noexcept { return *this >= long2(n); } + + static const long2 zero, one, minusOne, min, max, left, right, bottom, top; +}; + +inline const long2 long2::zero = long2(0); +inline const long2 long2::one = long2(1); +inline const long2 long2::minusOne = long2(-1); +inline const long2 long2::min = long2(INT64_MIN); +inline const long2 long2::max = long2(INT64_MAX); +inline const long2 long2::left = long2(-1, 0); +inline const long2 long2::right = long2(1, 0); +inline const long2 long2::bottom = long2(0, -1); +inline const long2 long2::top = long2(0, 1); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 64-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] long3 +{ + int64 x; /**< First vector component. */ + int64 y; /**< Second vector component. */ + int64 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz target value for all vector components + */ + constexpr explicit long3(int64 xyz = 0) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr long3(int64 x, int64 y, int64 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr long3(long2 xy, int64 z) noexcept : x(xy.x), y(xy.y), z(x) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr long3(int64 x, long2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(ulong3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(int3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(uint3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(short3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(ushort3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(sbyte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 64-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr long3(byte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int64& operator[](psize i) noexcept + { + assert(i <= 2); + return ((int64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int64 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((int64*)this)[i]; + } + + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator long2() const noexcept { return long2(x, y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr long3 operator+(long3 v) const noexcept { return long3(x + v.x, y + v.y, z + v.z); } + constexpr long3 operator-(long3 v) const noexcept { return long3(x - v.x, y - v.y, z - v.z); } + constexpr long3 operator*(long3 v) const noexcept { return long3(x * v.x, y * v.y, z * v.z); } + constexpr long3 operator/(long3 v) const noexcept { return long3(x / v.x, y / v.y, z / v.z); } + constexpr long3 operator%(long3 v) const noexcept { return long3(x % v.x, y % v.y, z % v.z); } + constexpr long3 operator&(long3 v) const noexcept { return long3(x & v.x, y & v.y, z & v.z); } + constexpr long3 operator|(long3 v) const noexcept { return long3(x | v.x, y | v.y, z | v.z); } + constexpr long3 operator^(long3 v) const noexcept { return long3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr long3 operator>>(long3 v) const noexcept { return long3(x >> v.x, y >> v.y, z >> v.z); } + constexpr long3 operator<<(long3 v) const noexcept { return long3(x << v.x, y << v.y, z << v.z); } + constexpr long3 operator+(int64 n) const noexcept { return long3(x + n, y + n, z + n); } + constexpr long3 operator-(int64 n) const noexcept { return long3(x - n, y - n, z - n); } + constexpr long3 operator*(int64 n) const noexcept { return long3(x * n, y * n, z * n); } + constexpr long3 operator/(int64 n) const noexcept { return long3(x / n, y / n, z / n); } + constexpr long3 operator%(int64 n) const noexcept { return long3(x % n, y % n, z % n); } + constexpr long3 operator&(int64 n) const noexcept { return long3(x & n, y & n, z & n); } + constexpr long3 operator|(int64 n) const noexcept { return long3(x | n, y | n, z | n); } + constexpr long3 operator^(int64 n) const noexcept { return long3(x ^ n, y ^ n, z ^ n); } + constexpr long3 operator>>(int64 n) const noexcept { return long3(x >> n, y >> n, z >> n); } + constexpr long3 operator<<(int64 n) const noexcept { return long3(x << n, y << n, z << n); } + constexpr long3 operator-() const noexcept { return long3(-x, -y, -z); } + constexpr long3 operator!() const noexcept { return long3(!x, !y, !z); } + constexpr long3 operator~() const noexcept { return long3(~x, ~y, ~z); } + long3& operator+=(long3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + long3& operator-=(long3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + long3& operator*=(long3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + long3& operator/=(long3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + long3& operator%=(long3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + long3& operator&=(long3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + long3& operator|=(long3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + long3& operator^=(long3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + long3& operator>>=(long3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + long3& operator<<=(long3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + long3& operator+=(int64 n) noexcept { x += n; y += n; z += n; return *this; } + long3& operator-=(int64 n) noexcept { x -= n; y -= n; z -= n; return *this; } + long3& operator*=(int64 n) noexcept { x *= n; y *= n; z *= n; return *this; } + long3& operator/=(int64 n) noexcept { x /= n; y /= n; z /= n; return *this; } + long3& operator%=(int64 n) noexcept { x %= n; y %= n; z %= n; return *this; } + long3& operator&=(int64 n) noexcept { x &= n; y &= n; z &= n; return *this; } + long3& operator|=(int64 n) noexcept { x |= n; y |= n; z |= n; return *this; } + long3& operator^=(int64 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + long3& operator>>=(int64 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + long3& operator<<=(int64 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + long3& operator=(int64 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(long3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(long3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr ulong3 operator<(long3 v) const noexcept + { + return ulong3(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0, z < v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator>(long3 v) const noexcept + { + return ulong3(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0, z > v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator<=(long3 v) const noexcept + { + return ulong3(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0, z <= v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator>=(long3 v) const noexcept + { + return ulong3(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0, z >= v.z ? UINT64_MAX : 0); + } + constexpr bool operator==(int64 n) const noexcept { return *this == long3(n); } + constexpr bool operator!=(int64 n) const noexcept { return *this != long3(n); } + constexpr ulong3 operator<(int64 n) const noexcept { return *this < long3(n); } + constexpr ulong3 operator>(int64 n) const noexcept { return *this > long3(n); } + constexpr ulong3 operator<=(int64 n) const noexcept { return *this <= long3(n); } + constexpr ulong3 operator>=(int64 n) const noexcept { return *this >= long3(n); } + + static const long3 zero, one, minusOne, min, max, left, right, bottom, top, back, front; +}; + +inline const long3 long3::zero = long3(0); +inline const long3 long3::one = long3(1); +inline const long3 long3::minusOne = long3(-1); +inline const long3 long3::min = long3(INT64_MIN); +inline const long3 long3::max = long3(INT64_MAX); +inline const long3 long3::left = long3(-1, 0, 0); +inline const long3 long3::right = long3(1, 0, 0); +inline const long3 long3::bottom = long3(0, -1, 0); +inline const long3 long3::top = long3(0, 1, 0); +inline const long3 long3::back = long3(0, 0, -1); +inline const long3 long3::front = long3(0, 0, 1); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 64-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] long4 +{ + int64 x; /**< First vector component. */ + int64 y; /**< Second vector component. */ + int64 z; /**< Third vector component. */ + int64 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit long4(int64 xyzw = 0) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr long4(int64 x, int64 y, int64 z, int64 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr long4(long2 xy, int64 z, int64 w) noexcept: x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr long4(int64 x, long2 yz, int64 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr long4(int64 x, int64 y, long2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr long4(long2 xy, long2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr long4(long3 xyz, int64 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * + * @param x first vector component value + * @param[in] yzw second, third and fourth vector component value + */ + constexpr long4(int64 x, long3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(ulong4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(int4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(uint4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(short4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(ushort4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(sbyte4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 64-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr long4(byte4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int64& operator[](psize i) noexcept + { + assert(i <= 3); + return ((int64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int64 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((int64*)this)[i]; + } + + constexpr explicit operator ulong4() const noexcept { return ulong4((uint64)x, (uint64)y, (uint64)z, (uint64)w); } + constexpr explicit operator int4() const noexcept { return int4((int32)x, (int32)y, (int32)z, (int32)w); } + constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator long3() const noexcept { return long3(x, y, z); } + constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator long2() const noexcept { return long2(x, y); } + constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr long4 operator+(long4 v) const noexcept { return long4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr long4 operator-(long4 v) const noexcept { return long4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr long4 operator*(long4 v) const noexcept { return long4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr long4 operator/(long4 v) const noexcept { return long4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr long4 operator%(long4 v) const noexcept { return long4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr long4 operator&(long4 v) const noexcept { return long4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr long4 operator|(long4 v) const noexcept { return long4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr long4 operator^(long4 v) const noexcept { return long4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr long4 operator>>(long4 v) const noexcept { return long4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr long4 operator<<(long4 v) const noexcept { return long4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr long4 operator+(int64 n) const noexcept { return long4(x + n, y + n, z + n, w + n); } + constexpr long4 operator-(int64 n) const noexcept { return long4(x - n, y - n, z - n, w - n); } + constexpr long4 operator*(int64 n) const noexcept { return long4(x * n, y * n, z * n, w * n); } + constexpr long4 operator/(int64 n) const noexcept { return long4(x / n, y / n, z / n, w / n); } + constexpr long4 operator%(int64 n) const noexcept { return long4(x % n, y % n, z % n, w % n); } + constexpr long4 operator&(int64 n) const noexcept { return long4(x & n, y & n, z & n, w & n); } + constexpr long4 operator|(int64 n) const noexcept { return long4(x | n, y | n, z | n, w | n); } + constexpr long4 operator^(int64 n) const noexcept { return long4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr long4 operator>>(int64 n) const noexcept { return long4(x >> n, y >> n, z >> n, w >> n); } + constexpr long4 operator<<(int64 n) const noexcept { return long4(x << n, y << n, z << n, w << n); } + constexpr long4 operator-() const noexcept { return long4(-x, -y, -z, -w); } + constexpr long4 operator!() const noexcept { return long4(!x, !y, !z, !w); } + constexpr long4 operator~() const noexcept { return long4(~x, ~y, ~z, ~w); } + long4& operator+=(long4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + long4& operator-=(long4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + long4& operator*=(long4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + long4& operator/=(long4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + long4& operator%=(long4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + long4& operator&=(long4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + long4& operator|=(long4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + long4& operator^=(long4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + long4& operator>>=(long4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + long4& operator<<=(long4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + long4& operator+=(int64 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + long4& operator-=(int64 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + long4& operator*=(int64 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + long4& operator/=(int64 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + long4& operator%=(int64 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + long4& operator&=(int64 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + long4& operator|=(int64 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + long4& operator^=(int64 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + long4& operator>>=(int64 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + long4& operator<<=(int64 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + long4& operator=(int64 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(long4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(long4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr ulong4 operator<(long4 v) const noexcept + { + return ulong4(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0, + z < v.z ? UINT64_MAX : 0, w < v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator>(long4 v) const noexcept + { + return ulong4(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0, + z > v.z ? UINT64_MAX : 0, w > v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator<=(long4 v) const noexcept + { + return ulong4(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0, + z <= v.z ? UINT64_MAX : 0, w <= v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator>=(long4 v) const noexcept + { + return ulong4(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0, + z >= v.z ? UINT64_MAX : 0, w >= v.w ? UINT64_MAX : 0); + } + constexpr bool operator==(int64 n) const noexcept { return *this == long4(n); } + constexpr bool operator!=(int64 n) const noexcept { return *this != long4(n); } + constexpr ulong4 operator<(int64 n) const noexcept { return *this < long4(n); } + constexpr ulong4 operator>(int64 n) const noexcept { return *this > long4(n); } + constexpr ulong4 operator<=(int64 n) const noexcept { return *this <= long4(n); } + constexpr ulong4 operator>=(int64 n) const noexcept { return *this >= long4(n); } + + static const long4 zero, one, minusOne, min, max; +}; + +inline const long4 long4::zero = long4(0); +inline const long4 long4::one = long4(1); +inline const long4 long4::minusOne = long4(-1); +inline const long4 long4::min = long4(INT64_MIN); +inline const long4 long4::max = long4(INT64_MAX); + +//********************************************************************************************************************** +static constexpr long2 operator+(int64 n, long2 v) noexcept { return long2(n) + v; } +static constexpr long2 operator-(int64 n, long2 v) noexcept { return long2(n) - v; } +static constexpr long2 operator*(int64 n, long2 v) noexcept { return long2(n) * v; } +static constexpr long2 operator/(int64 n, long2 v) noexcept { return long2(n) / v; } +static constexpr long2 operator%(int64 n, long2 v) noexcept { return long2(n) % v; } +static constexpr long2 operator&(int64 n, long2 v) noexcept { return long2(n) & v; } +static constexpr long2 operator|(int64 n, long2 v) noexcept { return long2(n) | v; } +static constexpr long2 operator^(int64 n, long2 v) noexcept { return long2(n) ^ v; } +static constexpr long2 operator>>(int64 n, long2 v) noexcept { return long2(n) >> v; } +static constexpr long2 operator<<(int64 n, long2 v) noexcept { return long2(n) << v; } +static constexpr bool operator==(int64 n, long2 v) noexcept { return long2(n) == v; } +static constexpr bool operator!=(int64 n, long2 v) noexcept { return long2(n) != v; } +static constexpr ulong2 operator<(int64 n, long2 v) noexcept { return long2(n) < v; } +static constexpr ulong2 operator>(int64 n, long2 v) noexcept { return long2(n) > v; } +static constexpr ulong2 operator<=(int64 n, long2 v) noexcept { return long2(n) <= v; } +static constexpr ulong2 operator>=(int64 n, long2 v) noexcept { return long2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(long2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong2 equal(long2 a, long2 b) noexcept +{ + return ulong2(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong2 notEqual(long2 a, long2 b) noexcept +{ + return ulong2(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(long2 a, long2 b) noexcept { return memcmp(&a, &b, sizeof(long2)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr long2 select(ulong2 c, long2 t, long2 f) noexcept +{ + return long2(c.x & 0x8000000000000000u ? t.x : f.x, c.y & 0x8000000000000000u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr long2 min(long2 a, long2 b) noexcept { return long2(std::min(a.x, b.x), std::min(a.y, b.y)); } +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr long2 max(long2 a, long2 b) noexcept { return long2(std::max(a.x, b.x), std::max(a.y, b.y)); } +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr long2 min(long2 a, long2 b, long2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr long2 max(long2 a, long2 b, long2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr long2 clamp(long2 v, long2 min, long2 max) noexcept +{ + return long2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr long3 operator+(int64 n, long3 v) noexcept { return long3(n) + v; } +static constexpr long3 operator-(int64 n, long3 v) noexcept { return long3(n) - v; } +static constexpr long3 operator*(int64 n, long3 v) noexcept { return long3(n) * v; } +static constexpr long3 operator/(int64 n, long3 v) noexcept { return long3(n) / v; } +static constexpr long3 operator%(int64 n, long3 v) noexcept { return long3(n) % v; } +static constexpr long3 operator&(int64 n, long3 v) noexcept { return long3(n) & v; } +static constexpr long3 operator|(int64 n, long3 v) noexcept { return long3(n) | v; } +static constexpr long3 operator^(int64 n, long3 v) noexcept { return long3(n) ^ v; } +static constexpr long3 operator>>(int64 n, long3 v) noexcept { return long3(n) >> v; } +static constexpr long3 operator<<(int64 n, long3 v) noexcept { return long3(n) << v; } +static constexpr bool operator==(int64 n, long3 v) noexcept { return long3(n) == v; } +static constexpr bool operator!=(int64 n, long3 v) noexcept { return long3(n) != v; } +static constexpr ulong3 operator<(int64 n, long3 v) noexcept { return long3(n) < v; } +static constexpr ulong3 operator>(int64 n, long3 v) noexcept { return long3(n) > v; } +static constexpr ulong3 operator<=(int64 n, long3 v) noexcept { return long3(n) <= v; } +static constexpr ulong3 operator>=(int64 n, long3 v) noexcept { return long3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(long3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong3 equal(long3 a, long3 b) noexcept +{ + return ulong3(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0, a.z == b.z ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong3 notEqual(long3 a, long3 b) noexcept +{ + return ulong3(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0, a.z != b.z ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const long3& a, const long3& b) noexcept { return memcmp(&a, &b, sizeof(long3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr long3 select(ulong3 c, long3 t, long3 f) noexcept +{ + return long3(c.x & 0x8000000000000000u ? t.x : f.x, + c.y & 0x8000000000000000u ? t.y : f.y, c.z & 0x8000000000000000u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr long3 min(long3 a, long3 b) noexcept +{ + return long3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr long3 max(long3 a, long3 b) noexcept +{ + return long3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr long3 min(long3 a, long3 b, long3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr long3 max(long3 a, long3 b, long3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr long3 clamp(long3 v, long3 min, long3 max) noexcept +{ + return long3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr long4 operator+(int64 n, long4 v) noexcept { return long4(n) + v; } +static constexpr long4 operator-(int64 n, long4 v) noexcept { return long4(n) - v; } +static constexpr long4 operator*(int64 n, long4 v) noexcept { return long4(n) * v; } +static constexpr long4 operator/(int64 n, long4 v) noexcept { return long4(n) / v; } +static constexpr long4 operator%(int64 n, long4 v) noexcept { return long4(n) % v; } +static constexpr long4 operator&(int64 n, long4 v) noexcept { return long4(n) & v; } +static constexpr long4 operator|(int64 n, long4 v) noexcept { return long4(n) | v; } +static constexpr long4 operator^(int64 n, long4 v) noexcept { return long4(n) ^ v; } +static constexpr long4 operator>>(int64 n, long4 v) noexcept { return long4(n) >> v; } +static constexpr long4 operator<<(int64 n, long4 v) noexcept { return long4(n) << v; } +static constexpr bool operator==(int64 n, long4 v) noexcept { return long4(n) == v; } +static constexpr bool operator!=(int64 n, long4 v) noexcept { return long4(n) != v; } +static constexpr ulong4 operator<(int64 n, long4 v) noexcept { return long4(n) < v; } +static constexpr ulong4 operator>(int64 n, long4 v) noexcept { return long4(n) > v; } +static constexpr ulong4 operator<=(int64 n, long4 v) noexcept { return long4(n) <= v; } +static constexpr ulong4 operator>=(int64 n, long4 v) noexcept { return long4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(long4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong4 equal(long4 a, long4 b) noexcept +{ + return ulong4(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0, + a.z == b.z ? UINT64_MAX : 0, a.w == b.w ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong4 notEqual(long4 a, long4 b) noexcept +{ + return ulong4(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0, + a.z != b.z ? UINT64_MAX : 0, a.w != b.w ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const long4& a, const long4& b) noexcept { return memcmp(&a, &b, sizeof(long4)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr long4 select(ulong4 c, long4 t, long4 f) noexcept +{ + return long4(c.x & 0x8000000000000000u ? t.x : f.x, c.y & 0x8000000000000000u ? t.y : f.y, + c.z & 0x8000000000000000u ? t.z : f.z, c.w & 0x8000000000000000u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr long4 min(long4 a, long4 b) noexcept +{ + return long4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr long4 max(long4 a, long4 b) noexcept +{ + return long4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr long4 min(long4 a, long4 b, long4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr long4 max(long4 a, long4 b, long4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr long4 clamp(long4 v, long4 min, long4 max) noexcept +{ + return long4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/sbyte.hpp b/include/math/vector/sbyte.hpp new file mode 100644 index 0000000..f6f3585 --- /dev/null +++ b/include/math/vector/sbyte.hpp @@ -0,0 +1,835 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common signed integer 8 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/vector/byte.hpp" + +namespace math +{ + +/** + * @brief A 2-component vector of 8-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] sbyte2 +{ + int8 x; /**< First vector component. */ + int8 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 8-bit signed integer values. + * @param xy target value for all vector components + */ + constexpr explicit sbyte2(int8 xy = 0) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr sbyte2(int8 x, int8 y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 8-bit signed integer values. + * @param xyzw first and second vector component value + */ + constexpr sbyte2(byte2 xy) noexcept : x((int8)xy.x), y((int8)xy.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int8& operator[](psize i) noexcept + { + assert(i <= 1); + return ((int8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int8 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((int8*)this)[i]; + } + + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr sbyte2 operator+(sbyte2 v) const noexcept { return sbyte2(x + v.x, y + v.y); } + constexpr sbyte2 operator-(sbyte2 v) const noexcept { return sbyte2(x - v.x, y - v.y); } + constexpr sbyte2 operator*(sbyte2 v) const noexcept { return sbyte2(x * v.x, y * v.y); } + constexpr sbyte2 operator/(sbyte2 v) const noexcept { return sbyte2(x / v.x, y / v.y); } + constexpr sbyte2 operator%(sbyte2 v) const noexcept { return sbyte2(x % v.x, y % v.y); } + constexpr sbyte2 operator&(sbyte2 v) const noexcept { return sbyte2(x & v.x, y & v.y); } + constexpr sbyte2 operator|(sbyte2 v) const noexcept { return sbyte2(x | v.x, y | v.y); } + constexpr sbyte2 operator^(sbyte2 v) const noexcept { return sbyte2(x ^ v.x, y ^ v.y); } + constexpr sbyte2 operator>>(sbyte2 v) const noexcept { return sbyte2(x >> v.x, y >> v.y); } + constexpr sbyte2 operator<<(sbyte2 v) const noexcept { return sbyte2(x << v.x, y << v.y); } + constexpr sbyte2 operator+(int8 n) const noexcept { return sbyte2(x + n, y + n); } + constexpr sbyte2 operator-(int8 n) const noexcept { return sbyte2(x - n, y - n); } + constexpr sbyte2 operator*(int8 n) const noexcept { return sbyte2(x * n, y * n); } + constexpr sbyte2 operator/(int8 n) const noexcept { return sbyte2(x / n, y / n); } + constexpr sbyte2 operator%(int8 n) const noexcept { return sbyte2(x % n, y % n); } + constexpr sbyte2 operator&(int8 n) const noexcept { return sbyte2(x & n, y & n); } + constexpr sbyte2 operator|(int8 n) const noexcept { return sbyte2(x | n, y | n); } + constexpr sbyte2 operator^(int8 n) const noexcept { return sbyte2(x ^ n, y ^ n); } + constexpr sbyte2 operator>>(int8 n) const noexcept { return sbyte2(x >> n, y >> n); } + constexpr sbyte2 operator<<(int8 n) const noexcept { return sbyte2(x << n, y << n); } + constexpr sbyte2 operator-() const noexcept { return sbyte2(-x, -y); } + constexpr sbyte2 operator!() const noexcept { return sbyte2(!x, !y); } + constexpr sbyte2 operator~() const noexcept { return sbyte2(~x, ~y); } + sbyte2& operator+=(sbyte2 v) noexcept { x += v.x; y += v.y; return *this; } + sbyte2& operator-=(sbyte2 v) noexcept { x -= v.x; y -= v.y; return *this; } + sbyte2& operator*=(sbyte2 v) noexcept { x *= v.x; y *= v.y; return *this; } + sbyte2& operator/=(sbyte2 v) noexcept { x /= v.x; y /= v.y; return *this; } + sbyte2& operator%=(sbyte2 v) noexcept { x %= v.x; y %= v.y; return *this; } + sbyte2& operator&=(sbyte2 v) noexcept { x &= v.x; y &= v.y; return *this; } + sbyte2& operator|=(sbyte2 v) noexcept { x |= v.x; y |= v.y; return *this; } + sbyte2& operator^=(sbyte2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + sbyte2& operator>>=(sbyte2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + sbyte2& operator<<=(sbyte2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + sbyte2& operator+=(int8 n) noexcept { x += n; y += n; return *this; } + sbyte2& operator-=(int8 n) noexcept { x -= n; y -= n; return *this; } + sbyte2& operator*=(int8 n) noexcept { x *= n; y *= n; return *this; } + sbyte2& operator/=(int8 n) noexcept { x /= n; y /= n; return *this; } + sbyte2& operator%=(int8 n) noexcept { x %= n; y %= n; return *this; } + sbyte2& operator&=(int8 n) noexcept { x &= n; y &= n; return *this; } + sbyte2& operator|=(int8 n) noexcept { x |= n; y |= n; return *this; } + sbyte2& operator^=(int8 n) noexcept { x ^= n; y ^= n; return *this; } + sbyte2& operator>>=(int8 n) noexcept { x >>= n; y >>= n; return *this; } + sbyte2& operator<<=(int8 n) noexcept { x <<= n; y <<= n; return *this; } + sbyte2& operator=(int8 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(sbyte2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(sbyte2 v) const noexcept { return x != v.x || y != v.y; } + constexpr byte2 operator<(sbyte2 v) const noexcept + { + return byte2(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator>(sbyte2 v) const noexcept + { + return byte2(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator<=(sbyte2 v) const noexcept + { + return byte2(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0); + } + constexpr byte2 operator>=(sbyte2 v) const noexcept + { + return byte2(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0); + } + constexpr bool operator==(int8 n) const noexcept { return *this == sbyte2(n); } + constexpr bool operator!=(int8 n) const noexcept { return *this != sbyte2(n); } + constexpr byte2 operator<(int8 n) const noexcept { return *this < sbyte2(n); } + constexpr byte2 operator>(int8 n) const noexcept { return *this > sbyte2(n); } + constexpr byte2 operator<=(int8 n) const noexcept { return *this <= sbyte2(n); } + constexpr byte2 operator>=(int8 n) const noexcept { return *this >= sbyte2(n); } + + static const sbyte2 zero, one, minusOne, min, max, left, right, bottom, top; +}; + +inline const sbyte2 sbyte2::zero = sbyte2(0); +inline const sbyte2 sbyte2::one = sbyte2(1); +inline const sbyte2 sbyte2::minusOne = sbyte2(-1); +inline const sbyte2 sbyte2::min = sbyte2(INT8_MIN); +inline const sbyte2 sbyte2::max = sbyte2(INT8_MAX); +inline const sbyte2 sbyte2::left = sbyte2(-1, 0); +inline const sbyte2 sbyte2::right = sbyte2(1, 0); +inline const sbyte2 sbyte2::bottom = sbyte2(0, -1); +inline const sbyte2 sbyte2::top = sbyte2(0, 1); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 8-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] sbyte3 +{ + int8 x; /**< First vector component. */ + int8 y; /**< Second vector component. */ + int8 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 8-bit signed integer values. + * @param xyz target value for all vector components + */ + constexpr explicit sbyte3(int8 xyz = 0) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr sbyte3(int8 x, int8 y, int8 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 8-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr sbyte3(sbyte2 xy, int8 z) noexcept : x(xy.x), y(xy.y), z(x) { } + /** + * @brief Creates a new 3-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr sbyte3(int8 x, sbyte2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 8-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr sbyte3(byte3 xyz) noexcept : x((int8)xyz.x), y((int8)xyz.y), z((int8)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int8& operator[](psize i) noexcept + { + assert(i <= 2); + return ((int8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int8 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((int8*)this)[i]; + } + + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2(x, y); } + + //****************************************************************************************************************** + constexpr sbyte3 operator+(sbyte3 v) const noexcept { return sbyte3(x + v.x, y + v.y, z + v.z); } + constexpr sbyte3 operator-(sbyte3 v) const noexcept { return sbyte3(x - v.x, y - v.y, z - v.z); } + constexpr sbyte3 operator*(sbyte3 v) const noexcept { return sbyte3(x * v.x, y * v.y, z * v.z); } + constexpr sbyte3 operator/(sbyte3 v) const noexcept { return sbyte3(x / v.x, y / v.y, z / v.z); } + constexpr sbyte3 operator%(sbyte3 v) const noexcept { return sbyte3(x % v.x, y % v.y, z % v.z); } + constexpr sbyte3 operator&(sbyte3 v) const noexcept { return sbyte3(x & v.x, y & v.y, z & v.z); } + constexpr sbyte3 operator|(sbyte3 v) const noexcept { return sbyte3(x | v.x, y | v.y, z | v.z); } + constexpr sbyte3 operator^(sbyte3 v) const noexcept { return sbyte3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr sbyte3 operator>>(sbyte3 v) const noexcept { return sbyte3(x >> v.x, y >> v.y, z >> v.z); } + constexpr sbyte3 operator<<(sbyte3 v) const noexcept { return sbyte3(x << v.x, y << v.y, z << v.z); } + constexpr sbyte3 operator+(int8 n) const noexcept { return sbyte3(x + n, y + n, z + n); } + constexpr sbyte3 operator-(int8 n) const noexcept { return sbyte3(x - n, y - n, z - n); } + constexpr sbyte3 operator*(int8 n) const noexcept { return sbyte3(x * n, y * n, z * n); } + constexpr sbyte3 operator/(int8 n) const noexcept { return sbyte3(x / n, y / n, z / n); } + constexpr sbyte3 operator%(int8 n) const noexcept { return sbyte3(x % n, y % n, z % n); } + constexpr sbyte3 operator&(int8 n) const noexcept { return sbyte3(x & n, y & n, z & n); } + constexpr sbyte3 operator|(int8 n) const noexcept { return sbyte3(x | n, y | n, z | n); } + constexpr sbyte3 operator^(int8 n) const noexcept { return sbyte3(x ^ n, y ^ n, z ^ n); } + constexpr sbyte3 operator>>(int8 n) const noexcept { return sbyte3(x >> n, y >> n, z >> n); } + constexpr sbyte3 operator<<(int8 n) const noexcept { return sbyte3(x << n, y << n, z << n); } + constexpr sbyte3 operator-() const noexcept { return sbyte3(-x, -y, -z); } + constexpr sbyte3 operator!() const noexcept { return sbyte3(!x, !y, !z); } + constexpr sbyte3 operator~() const noexcept { return sbyte3(~x, ~y, ~z); } + sbyte3& operator+=(sbyte3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + sbyte3& operator-=(sbyte3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + sbyte3& operator*=(sbyte3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + sbyte3& operator/=(sbyte3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + sbyte3& operator%=(sbyte3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + sbyte3& operator&=(sbyte3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + sbyte3& operator|=(sbyte3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + sbyte3& operator^=(sbyte3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + sbyte3& operator>>=(sbyte3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + sbyte3& operator<<=(sbyte3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + sbyte3& operator+=(int8 n) noexcept { x += n; y += n; z += n; return *this; } + sbyte3& operator-=(int8 n) noexcept { x -= n; y -= n; z -= n; return *this; } + sbyte3& operator*=(int8 n) noexcept { x *= n; y *= n; z *= n; return *this; } + sbyte3& operator/=(int8 n) noexcept { x /= n; y /= n; z /= n; return *this; } + sbyte3& operator%=(int8 n) noexcept { x %= n; y %= n; z %= n; return *this; } + sbyte3& operator&=(int8 n) noexcept { x &= n; y &= n; z &= n; return *this; } + sbyte3& operator|=(int8 n) noexcept { x |= n; y |= n; z |= n; return *this; } + sbyte3& operator^=(int8 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + sbyte3& operator>>=(int8 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + sbyte3& operator<<=(int8 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + sbyte3& operator=(int8 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(sbyte3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(sbyte3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr byte3 operator<(sbyte3 v) const noexcept + { + return byte3(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0, z < v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator>(sbyte3 v) const noexcept + { + return byte3(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0, z > v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator<=(sbyte3 v) const noexcept + { + return byte3(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0, z <= v.z ? UINT8_MAX : 0); + } + constexpr byte3 operator>=(sbyte3 v) const noexcept + { + return byte3(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0, z >= v.z ? UINT8_MAX : 0); + } + constexpr bool operator==(int8 n) const noexcept { return *this == sbyte3(n); } + constexpr bool operator!=(int8 n) const noexcept { return *this != sbyte3(n); } + constexpr byte3 operator<(int8 n) const noexcept { return *this < sbyte3(n); } + constexpr byte3 operator>(int8 n) const noexcept { return *this > sbyte3(n); } + constexpr byte3 operator<=(int8 n) const noexcept { return *this <= sbyte3(n); } + constexpr byte3 operator>=(int8 n) const noexcept { return *this >= sbyte3(n); } + + static const sbyte3 zero, one, minusOne, min, max, left, right, bottom, top, back, front; +}; + +inline const sbyte3 sbyte3::zero = sbyte3(0); +inline const sbyte3 sbyte3::one = sbyte3(1); +inline const sbyte3 sbyte3::minusOne = sbyte3(-1); +inline const sbyte3 sbyte3::min = sbyte3(INT8_MIN); +inline const sbyte3 sbyte3::max = sbyte3(INT8_MAX); +inline const sbyte3 sbyte3::left = sbyte3(-1, 0, 0); +inline const sbyte3 sbyte3::right = sbyte3(1, 0, 0); +inline const sbyte3 sbyte3::bottom = sbyte3(0, -1, 0); +inline const sbyte3 sbyte3::top = sbyte3(0, 1, 0); +inline const sbyte3 sbyte3::back = sbyte3(0, 0, -1); +inline const sbyte3 sbyte3::front = sbyte3(0, 0, 1); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 8-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] sbyte4 +{ + int8 x; /**< First vector component. */ + int8 y; /**< Second vector component. */ + int8 z; /**< Third vector component. */ + int8 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit sbyte4(int8 xyzw = 0) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr sbyte4(int8 x, int8 y, int8 z, int8 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr sbyte4(sbyte2 xy, int8 z, int8 w) noexcept: x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr sbyte4(int8 x, sbyte2 yz, int8 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr sbyte4(int8 x, int8 y, sbyte2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr sbyte4(sbyte2 xy, sbyte2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr sbyte4(sbyte3 xyz, int8 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * + * @param x first vector component value + * @param[in] yzw second, third and fourth vector component value + */ + constexpr sbyte4(int8 x, sbyte3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 8-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr sbyte4(byte4 xyzw) noexcept : x((int8)xyzw.x), y((int8)xyzw.y), z((int8)xyzw.z), w((int8)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int8& operator[](psize i) noexcept + { + assert(i <= 3); + return ((int8*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int8 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((int8*)this)[i]; + } + + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3(x, y, z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2(x, y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr sbyte4 operator+(sbyte4 v) const noexcept { return sbyte4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr sbyte4 operator-(sbyte4 v) const noexcept { return sbyte4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr sbyte4 operator*(sbyte4 v) const noexcept { return sbyte4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr sbyte4 operator/(sbyte4 v) const noexcept { return sbyte4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr sbyte4 operator%(sbyte4 v) const noexcept { return sbyte4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr sbyte4 operator&(sbyte4 v) const noexcept { return sbyte4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr sbyte4 operator|(sbyte4 v) const noexcept { return sbyte4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr sbyte4 operator^(sbyte4 v) const noexcept { return sbyte4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr sbyte4 operator>>(sbyte4 v) const noexcept { return sbyte4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr sbyte4 operator<<(sbyte4 v) const noexcept { return sbyte4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr sbyte4 operator+(int8 n) const noexcept { return sbyte4(x + n, y + n, z + n, w + n); } + constexpr sbyte4 operator-(int8 n) const noexcept { return sbyte4(x - n, y - n, z - n, w - n); } + constexpr sbyte4 operator*(int8 n) const noexcept { return sbyte4(x * n, y * n, z * n, w * n); } + constexpr sbyte4 operator/(int8 n) const noexcept { return sbyte4(x / n, y / n, z / n, w / n); } + constexpr sbyte4 operator%(int8 n) const noexcept { return sbyte4(x % n, y % n, z % n, w % n); } + constexpr sbyte4 operator&(int8 n) const noexcept { return sbyte4(x & n, y & n, z & n, w & n); } + constexpr sbyte4 operator|(int8 n) const noexcept { return sbyte4(x | n, y | n, z | n, w | n); } + constexpr sbyte4 operator^(int8 n) const noexcept { return sbyte4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr sbyte4 operator>>(int8 n) const noexcept { return sbyte4(x >> n, y >> n, z >> n, w >> n); } + constexpr sbyte4 operator<<(int8 n) const noexcept { return sbyte4(x << n, y << n, z << n, w << n); } + constexpr sbyte4 operator-() const noexcept { return sbyte4(-x, -y, -z, -w); } + constexpr sbyte4 operator!() const noexcept { return sbyte4(!x, !y, !z, !w); } + constexpr sbyte4 operator~() const noexcept { return sbyte4(~x, ~y, ~z, ~w); } + sbyte4& operator+=(sbyte4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + sbyte4& operator-=(sbyte4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + sbyte4& operator*=(sbyte4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + sbyte4& operator/=(sbyte4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + sbyte4& operator%=(sbyte4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + sbyte4& operator&=(sbyte4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + sbyte4& operator|=(sbyte4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + sbyte4& operator^=(sbyte4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + sbyte4& operator>>=(sbyte4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + sbyte4& operator<<=(sbyte4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + sbyte4& operator+=(int8 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + sbyte4& operator-=(int8 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + sbyte4& operator*=(int8 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + sbyte4& operator/=(int8 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + sbyte4& operator%=(int8 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + sbyte4& operator&=(int8 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + sbyte4& operator|=(int8 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + sbyte4& operator^=(int8 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + sbyte4& operator>>=(int8 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + sbyte4& operator<<=(int8 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + sbyte4& operator=(int8 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(sbyte4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(sbyte4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr byte4 operator<(sbyte4 v) const noexcept + { + return byte4(x < v.x ? UINT8_MAX : 0, y < v.y ? UINT8_MAX : 0, + z < v.z ? UINT8_MAX : 0, w < v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator>(sbyte4 v) const noexcept + { + return byte4(x > v.x ? UINT8_MAX : 0, y > v.y ? UINT8_MAX : 0, + z > v.z ? UINT8_MAX : 0, w > v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator<=(sbyte4 v) const noexcept + { + return byte4(x <= v.x ? UINT8_MAX : 0, y <= v.y ? UINT8_MAX : 0, + z <= v.z ? UINT8_MAX : 0, w <= v.w ? UINT8_MAX : 0); + } + constexpr byte4 operator>=(sbyte4 v) const noexcept + { + return byte4(x >= v.x ? UINT8_MAX : 0, y >= v.y ? UINT8_MAX : 0, + z >= v.z ? UINT8_MAX : 0, w >= v.w ? UINT8_MAX : 0); + } + constexpr bool operator==(int8 n) const noexcept { return *this == sbyte4(n); } + constexpr bool operator!=(int8 n) const noexcept { return *this != sbyte4(n); } + constexpr byte4 operator<(int8 n) const noexcept { return *this < sbyte4(n); } + constexpr byte4 operator>(int8 n) const noexcept { return *this > sbyte4(n); } + constexpr byte4 operator<=(int8 n) const noexcept { return *this <= sbyte4(n); } + constexpr byte4 operator>=(int8 n) const noexcept { return *this >= sbyte4(n); } + + static const sbyte4 zero, one, minusOne, min, max; +}; + +inline const sbyte4 sbyte4::zero = sbyte4(0); +inline const sbyte4 sbyte4::one = sbyte4(1); +inline const sbyte4 sbyte4::minusOne = sbyte4(-1); +inline const sbyte4 sbyte4::min = sbyte4(INT8_MIN); +inline const sbyte4 sbyte4::max = sbyte4(INT8_MAX); + +//********************************************************************************************************************** +static constexpr sbyte2 operator+(int8 n, sbyte2 v) noexcept { return sbyte2(n) + v; } +static constexpr sbyte2 operator-(int8 n, sbyte2 v) noexcept { return sbyte2(n) - v; } +static constexpr sbyte2 operator*(int8 n, sbyte2 v) noexcept { return sbyte2(n) * v; } +static constexpr sbyte2 operator/(int8 n, sbyte2 v) noexcept { return sbyte2(n) / v; } +static constexpr sbyte2 operator%(int8 n, sbyte2 v) noexcept { return sbyte2(n) % v; } +static constexpr sbyte2 operator&(int8 n, sbyte2 v) noexcept { return sbyte2(n) & v; } +static constexpr sbyte2 operator|(int8 n, sbyte2 v) noexcept { return sbyte2(n) | v; } +static constexpr sbyte2 operator^(int8 n, sbyte2 v) noexcept { return sbyte2(n) ^ v; } +static constexpr sbyte2 operator>>(int8 n, sbyte2 v) noexcept { return sbyte2(n) >> v; } +static constexpr sbyte2 operator<<(int8 n, sbyte2 v) noexcept { return sbyte2(n) << v; } +static constexpr bool operator==(int8 n, sbyte2 v) noexcept { return sbyte2(n) == v; } +static constexpr bool operator!=(int8 n, sbyte2 v) noexcept { return sbyte2(n) != v; } +static constexpr byte2 operator<(int8 n, sbyte2 v) noexcept { return sbyte2(n) < v; } +static constexpr byte2 operator>(int8 n, sbyte2 v) noexcept { return sbyte2(n) > v; } +static constexpr byte2 operator<=(int8 n, sbyte2 v) noexcept { return sbyte2(n) <= v; } +static constexpr byte2 operator>=(int8 n, sbyte2 v) noexcept { return sbyte2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(sbyte2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte2 equal(sbyte2 a, sbyte2 b) noexcept +{ + return byte2(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte2 notEqual(sbyte2 a, sbyte2 b) noexcept +{ + return byte2(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(sbyte2 a, sbyte2 b) noexcept { return *((const int16*)&a) < *((const int16*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr sbyte2 select(byte2 c, sbyte2 t, sbyte2 f) noexcept +{ + return sbyte2(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr sbyte2 min(sbyte2 a, sbyte2 b) noexcept { return sbyte2(std::min(a.x, b.x), std::min(a.y, b.y)); } +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr sbyte2 max(sbyte2 a, sbyte2 b) noexcept { return sbyte2(std::max(a.x, b.x), std::max(a.y, b.y)); } +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr sbyte2 min(sbyte2 a, sbyte2 b, sbyte2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr sbyte2 max(sbyte2 a, sbyte2 b, sbyte2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr sbyte2 clamp(sbyte2 v, sbyte2 min, sbyte2 max) noexcept +{ + return sbyte2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr sbyte3 operator+(int8 n, sbyte3 v) noexcept { return sbyte3(n) + v; } +static constexpr sbyte3 operator-(int8 n, sbyte3 v) noexcept { return sbyte3(n) - v; } +static constexpr sbyte3 operator*(int8 n, sbyte3 v) noexcept { return sbyte3(n) * v; } +static constexpr sbyte3 operator/(int8 n, sbyte3 v) noexcept { return sbyte3(n) / v; } +static constexpr sbyte3 operator%(int8 n, sbyte3 v) noexcept { return sbyte3(n) % v; } +static constexpr sbyte3 operator&(int8 n, sbyte3 v) noexcept { return sbyte3(n) & v; } +static constexpr sbyte3 operator|(int8 n, sbyte3 v) noexcept { return sbyte3(n) | v; } +static constexpr sbyte3 operator^(int8 n, sbyte3 v) noexcept { return sbyte3(n) ^ v; } +static constexpr sbyte3 operator>>(int8 n, sbyte3 v) noexcept { return sbyte3(n) >> v; } +static constexpr sbyte3 operator<<(int8 n, sbyte3 v) noexcept { return sbyte3(n) << v; } +static constexpr bool operator==(int8 n, sbyte3 v) noexcept { return sbyte3(n) == v; } +static constexpr bool operator!=(int8 n, sbyte3 v) noexcept { return sbyte3(n) != v; } +static constexpr byte3 operator<(int8 n, sbyte3 v) noexcept { return sbyte3(n) < v; } +static constexpr byte3 operator>(int8 n, sbyte3 v) noexcept { return sbyte3(n) > v; } +static constexpr byte3 operator<=(int8 n, sbyte3 v) noexcept { return sbyte3(n) <= v; } +static constexpr byte3 operator>=(int8 n, sbyte3 v) noexcept { return sbyte3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(sbyte3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte3 equal(sbyte3 a, sbyte3 b) noexcept +{ + return byte3(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0, a.z == b.z ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte3 notEqual(sbyte3 a, sbyte3 b) noexcept +{ + return byte3(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0, a.z != b.z ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const sbyte3& a, const sbyte3& b) noexcept { return memcmp(&a, &b, sizeof(sbyte3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr sbyte3 select(byte3 c, sbyte3 t, sbyte3 f) noexcept +{ + return sbyte3(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y, c.z & 0x80u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr sbyte3 min(sbyte3 a, sbyte3 b) noexcept +{ + return sbyte3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr sbyte3 max(sbyte3 a, sbyte3 b) noexcept +{ + return sbyte3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr sbyte3 min(sbyte3 a, sbyte3 b, sbyte3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr sbyte3 max(sbyte3 a, sbyte3 b, sbyte3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr sbyte3 clamp(sbyte3 v, sbyte3 min, sbyte3 max) noexcept +{ + return sbyte3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr sbyte4 operator+(int8 n, sbyte4 v) noexcept { return sbyte4(n) + v; } +static constexpr sbyte4 operator-(int8 n, sbyte4 v) noexcept { return sbyte4(n) - v; } +static constexpr sbyte4 operator*(int8 n, sbyte4 v) noexcept { return sbyte4(n) * v; } +static constexpr sbyte4 operator/(int8 n, sbyte4 v) noexcept { return sbyte4(n) / v; } +static constexpr sbyte4 operator%(int8 n, sbyte4 v) noexcept { return sbyte4(n) % v; } +static constexpr sbyte4 operator&(int8 n, sbyte4 v) noexcept { return sbyte4(n) & v; } +static constexpr sbyte4 operator|(int8 n, sbyte4 v) noexcept { return sbyte4(n) | v; } +static constexpr sbyte4 operator^(int8 n, sbyte4 v) noexcept { return sbyte4(n) ^ v; } +static constexpr sbyte4 operator>>(int8 n, sbyte4 v) noexcept { return sbyte4(n) >> v; } +static constexpr sbyte4 operator<<(int8 n, sbyte4 v) noexcept { return sbyte4(n) << v; } +static constexpr bool operator==(int8 n, sbyte4 v) noexcept { return sbyte4(n) == v; } +static constexpr bool operator!=(int8 n, sbyte4 v) noexcept { return sbyte4(n) != v; } +static constexpr byte4 operator<(int8 n, sbyte4 v) noexcept { return sbyte4(n) < v; } +static constexpr byte4 operator>(int8 n, sbyte4 v) noexcept { return sbyte4(n) > v; } +static constexpr byte4 operator<=(int8 n, sbyte4 v) noexcept { return sbyte4(n) <= v; } +static constexpr byte4 operator>=(int8 n, sbyte4 v) noexcept { return sbyte4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(sbyte4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte4 equal(sbyte4 a, sbyte4 b) noexcept +{ + return byte4(a.x == b.x ? UINT8_MAX : 0, a.y == b.y ? UINT8_MAX : 0, + a.z == b.z ? UINT8_MAX : 0, a.w == b.w ? UINT8_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static byte4 notEqual(sbyte4 a, sbyte4 b) noexcept +{ + return byte4(a.x != b.x ? UINT8_MAX : 0, a.y != b.y ? UINT8_MAX : 0, + a.z != b.z ? UINT8_MAX : 0, a.w != b.w ? UINT8_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const sbyte4& a, const sbyte4& b) noexcept { return *((const int32*)&a) < *((const int32*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr sbyte4 select(byte4 c, sbyte4 t, sbyte4 f) noexcept +{ + return sbyte4(c.x & 0x80u ? t.x : f.x, c.y & 0x80u ? t.y : f.y, c.z & 0x80u ? t.z : f.z, c.w & 0x80u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr sbyte4 min(sbyte4 a, sbyte4 b) noexcept +{ + return sbyte4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr sbyte4 max(sbyte4 a, sbyte4 b) noexcept +{ + return sbyte4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr sbyte4 min(sbyte4 a, sbyte4 b, sbyte4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr sbyte4 max(sbyte4 a, sbyte4 b, sbyte4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr sbyte4 clamp(sbyte4 v, sbyte4 min, sbyte4 max) noexcept +{ + return sbyte4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/short.hpp b/include/math/vector/short.hpp new file mode 100644 index 0000000..9a7248a --- /dev/null +++ b/include/math/vector/short.hpp @@ -0,0 +1,879 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common signed integer 16 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/vector/sbyte.hpp" +#include "math/vector/ushort.hpp" + +namespace math +{ + +/** + * @brief A 2-component vector of 16-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] short2 +{ + int16 x; /**< First vector component. */ + int16 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 16-bit signed integer values. + * @param xy target value for all vector components + */ + constexpr explicit short2(int16 xy = 0) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr short2(int16 x, int16 y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 16-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr short2(ushort2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr short2(sbyte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + /** + * @brief Creates a new 2-component vector of 16-bit signed integer values. + * @param xy first and second vector component value + */ + constexpr short2(byte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int16& operator[](psize i) noexcept + { + assert(i <= 1); + return ((int16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int16 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((int16*)this)[i]; + } + + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr short2 operator+(short2 v) const noexcept { return short2(x + v.x, y + v.y); } + constexpr short2 operator-(short2 v) const noexcept { return short2(x - v.x, y - v.y); } + constexpr short2 operator*(short2 v) const noexcept { return short2(x * v.x, y * v.y); } + constexpr short2 operator/(short2 v) const noexcept { return short2(x / v.x, y / v.y); } + constexpr short2 operator%(short2 v) const noexcept { return short2(x % v.x, y % v.y); } + constexpr short2 operator&(short2 v) const noexcept { return short2(x & v.x, y & v.y); } + constexpr short2 operator|(short2 v) const noexcept { return short2(x | v.x, y | v.y); } + constexpr short2 operator^(short2 v) const noexcept { return short2(x ^ v.x, y ^ v.y); } + constexpr short2 operator>>(short2 v) const noexcept { return short2(x >> v.x, y >> v.y); } + constexpr short2 operator<<(short2 v) const noexcept { return short2(x << v.x, y << v.y); } + constexpr short2 operator+(int16 n) const noexcept { return short2(x + n, y + n); } + constexpr short2 operator-(int16 n) const noexcept { return short2(x - n, y - n); } + constexpr short2 operator*(int16 n) const noexcept { return short2(x * n, y * n); } + constexpr short2 operator/(int16 n) const noexcept { return short2(x / n, y / n); } + constexpr short2 operator%(int16 n) const noexcept { return short2(x % n, y % n); } + constexpr short2 operator&(int16 n) const noexcept { return short2(x & n, y & n); } + constexpr short2 operator|(int16 n) const noexcept { return short2(x | n, y | n); } + constexpr short2 operator^(int16 n) const noexcept { return short2(x ^ n, y ^ n); } + constexpr short2 operator>>(int16 n) const noexcept { return short2(x >> n, y >> n); } + constexpr short2 operator<<(int16 n) const noexcept { return short2(x << n, y << n); } + constexpr short2 operator-() const noexcept { return short2(-x, -y); } + constexpr short2 operator!() const noexcept { return short2(!x, !y); } + constexpr short2 operator~() const noexcept { return short2(~x, ~y); } + short2& operator+=(short2 v) noexcept { x += v.x; y += v.y; return *this; } + short2& operator-=(short2 v) noexcept { x -= v.x; y -= v.y; return *this; } + short2& operator*=(short2 v) noexcept { x *= v.x; y *= v.y; return *this; } + short2& operator/=(short2 v) noexcept { x /= v.x; y /= v.y; return *this; } + short2& operator%=(short2 v) noexcept { x %= v.x; y %= v.y; return *this; } + short2& operator&=(short2 v) noexcept { x &= v.x; y &= v.y; return *this; } + short2& operator|=(short2 v) noexcept { x |= v.x; y |= v.y; return *this; } + short2& operator^=(short2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + short2& operator>>=(short2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + short2& operator<<=(short2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + short2& operator+=(int16 n) noexcept { x += n; y += n; return *this; } + short2& operator-=(int16 n) noexcept { x -= n; y -= n; return *this; } + short2& operator*=(int16 n) noexcept { x *= n; y *= n; return *this; } + short2& operator/=(int16 n) noexcept { x /= n; y /= n; return *this; } + short2& operator%=(int16 n) noexcept { x %= n; y %= n; return *this; } + short2& operator&=(int16 n) noexcept { x &= n; y &= n; return *this; } + short2& operator|=(int16 n) noexcept { x |= n; y |= n; return *this; } + short2& operator^=(int16 n) noexcept { x ^= n; y ^= n; return *this; } + short2& operator>>=(int16 n) noexcept { x >>= n; y >>= n; return *this; } + short2& operator<<=(int16 n) noexcept { x <<= n; y <<= n; return *this; } + short2& operator=(int16 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(short2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(short2 v) const noexcept { return x != v.x || y != v.y; } + constexpr ushort2 operator<(short2 v) const noexcept + { + return ushort2(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator>(short2 v) const noexcept + { + return ushort2(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator<=(short2 v) const noexcept + { + return ushort2(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator>=(short2 v) const noexcept + { + return ushort2(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0); + } + constexpr bool operator==(int16 n) const noexcept { return *this == short2(n); } + constexpr bool operator!=(int16 n) const noexcept { return *this != short2(n); } + constexpr ushort2 operator<(int16 n) const noexcept { return *this < short2(n); } + constexpr ushort2 operator>(int16 n) const noexcept { return *this > short2(n); } + constexpr ushort2 operator<=(int16 n) const noexcept { return *this <= short2(n); } + constexpr ushort2 operator>=(int16 n) const noexcept { return *this >= short2(n); } + + static const short2 zero, one, minusOne, min, max, left, right, bottom, top; +}; + +inline const short2 short2::zero = short2(0); +inline const short2 short2::one = short2(1); +inline const short2 short2::minusOne = short2(-1); +inline const short2 short2::min = short2(INT16_MIN); +inline const short2 short2::max = short2(INT16_MAX); +inline const short2 short2::left = short2(-1, 0); +inline const short2 short2::right = short2(1, 0); +inline const short2 short2::bottom = short2(0, -1); +inline const short2 short2::top = short2(0, 1); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 16-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] short3 +{ + int16 x; /**< First vector component. */ + int16 y; /**< Second vector component. */ + int16 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * @param xyz target value for all vector components + */ + constexpr explicit short3(int16 xyz = 0) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr short3(int16 x, int16 y, int16 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr short3(short2 xy, int16 z) noexcept : x(xy.x), y(xy.y), z(x) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr short3(int16 x, short2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr short3(ushort3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr short3(sbyte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } + /** + * @brief Creates a new 3-component vector of 16-bit signed integer values. + * @param xyz first, second and third vector component value + */ + constexpr short3(byte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int16& operator[](psize i) noexcept + { + assert(i <= 2); + return ((int16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int16 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((int16*)this)[i]; + } + + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator short2() const noexcept { return short2(x, y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr short3 operator+(short3 v) const noexcept { return short3(x + v.x, y + v.y, z + v.z); } + constexpr short3 operator-(short3 v) const noexcept { return short3(x - v.x, y - v.y, z - v.z); } + constexpr short3 operator*(short3 v) const noexcept { return short3(x * v.x, y * v.y, z * v.z); } + constexpr short3 operator/(short3 v) const noexcept { return short3(x / v.x, y / v.y, z / v.z); } + constexpr short3 operator%(short3 v) const noexcept { return short3(x % v.x, y % v.y, z % v.z); } + constexpr short3 operator&(short3 v) const noexcept { return short3(x & v.x, y & v.y, z & v.z); } + constexpr short3 operator|(short3 v) const noexcept { return short3(x | v.x, y | v.y, z | v.z); } + constexpr short3 operator^(short3 v) const noexcept { return short3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr short3 operator>>(short3 v) const noexcept { return short3(x >> v.x, y >> v.y, z >> v.z); } + constexpr short3 operator<<(short3 v) const noexcept { return short3(x << v.x, y << v.y, z << v.z); } + constexpr short3 operator+(int16 n) const noexcept { return short3(x + n, y + n, z + n); } + constexpr short3 operator-(int16 n) const noexcept { return short3(x - n, y - n, z - n); } + constexpr short3 operator*(int16 n) const noexcept { return short3(x * n, y * n, z * n); } + constexpr short3 operator/(int16 n) const noexcept { return short3(x / n, y / n, z / n); } + constexpr short3 operator%(int16 n) const noexcept { return short3(x % n, y % n, z % n); } + constexpr short3 operator&(int16 n) const noexcept { return short3(x & n, y & n, z & n); } + constexpr short3 operator|(int16 n) const noexcept { return short3(x | n, y | n, z | n); } + constexpr short3 operator^(int16 n) const noexcept { return short3(x ^ n, y ^ n, z ^ n); } + constexpr short3 operator>>(int16 n) const noexcept { return short3(x >> n, y >> n, z >> n); } + constexpr short3 operator<<(int16 n) const noexcept { return short3(x << n, y << n, z << n); } + constexpr short3 operator-() const noexcept { return short3(-x, -y, -z); } + constexpr short3 operator!() const noexcept { return short3(!x, !y, !z); } + constexpr short3 operator~() const noexcept { return short3(~x, ~y, ~z); } + short3& operator+=(short3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + short3& operator-=(short3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + short3& operator*=(short3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + short3& operator/=(short3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + short3& operator%=(short3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + short3& operator&=(short3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + short3& operator|=(short3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + short3& operator^=(short3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + short3& operator>>=(short3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + short3& operator<<=(short3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + short3& operator+=(int16 n) noexcept { x += n; y += n; z += n; return *this; } + short3& operator-=(int16 n) noexcept { x -= n; y -= n; z -= n; return *this; } + short3& operator*=(int16 n) noexcept { x *= n; y *= n; z *= n; return *this; } + short3& operator/=(int16 n) noexcept { x /= n; y /= n; z /= n; return *this; } + short3& operator%=(int16 n) noexcept { x %= n; y %= n; z %= n; return *this; } + short3& operator&=(int16 n) noexcept { x &= n; y &= n; z &= n; return *this; } + short3& operator|=(int16 n) noexcept { x |= n; y |= n; z |= n; return *this; } + short3& operator^=(int16 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + short3& operator>>=(int16 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + short3& operator<<=(int16 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + short3& operator=(int16 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(short3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(short3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr ushort3 operator<(short3 v) const noexcept + { + return ushort3(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0, z < v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator>(short3 v) const noexcept + { + return ushort3(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0, z > v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator<=(short3 v) const noexcept + { + return ushort3(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0, z <= v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator>=(short3 v) const noexcept + { + return ushort3(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0, z >= v.z ? UINT16_MAX : 0); + } + constexpr bool operator==(int16 n) const noexcept { return *this == short3(n); } + constexpr bool operator!=(int16 n) const noexcept { return *this != short3(n); } + constexpr ushort3 operator<(int16 n) const noexcept { return *this < short3(n); } + constexpr ushort3 operator>(int16 n) const noexcept { return *this > short3(n); } + constexpr ushort3 operator<=(int16 n) const noexcept { return *this <= short3(n); } + constexpr ushort3 operator>=(int16 n) const noexcept { return *this >= short3(n); } + + static const short3 zero, one, minusOne, min, max, left, right, bottom, top, back, front; +}; + +inline const short3 short3::zero = short3(0); +inline const short3 short3::one = short3(1); +inline const short3 short3::minusOne = short3(-1); +inline const short3 short3::min = short3(INT16_MIN); +inline const short3 short3::max = short3(INT16_MAX); +inline const short3 short3::left = short3(-1, 0, 0); +inline const short3 short3::right = short3(1, 0, 0); +inline const short3 short3::bottom = short3(0, -1, 0); +inline const short3 short3::top = short3(0, 1, 0); +inline const short3 short3::back = short3(0, 0, -1); +inline const short3 short3::front = short3(0, 0, 1); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 16-bit signed integer values. + * @details Commonly used to represent: points, positions, directions, velocities, etc. + */ +struct [[nodiscard]] short4 +{ + int16 x; /**< First vector component. */ + int16 y; /**< Second vector component. */ + int16 z; /**< Third vector component. */ + int16 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit short4(int16 xyzw = 0) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr short4(int16 x, int16 y, int16 z, int16 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr short4(short2 xy, int16 z, int16 w) noexcept: x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr short4(int16 x, short2 yz, int16 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr short4(int16 x, int16 y, short2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr short4(short2 xy, short2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr short4(short3 xyz, int16 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * + * @param x first vector component value + * @param[in] yzw second, third and fourth vector component value + */ + constexpr short4(int16 x, short3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr short4(ushort4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr short4(sbyte4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } + /** + * @brief Creates a new 4-component vector of 16-bit signed integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr short4(byte4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + int16& operator[](psize i) noexcept + { + assert(i <= 3); + return ((int16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + int16 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((int16*)this)[i]; + } + + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } + constexpr explicit operator short3() const noexcept { return short3(x, y, z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } + constexpr explicit operator short2() const noexcept { return short2(x, y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + //****************************************************************************************************************** + constexpr short4 operator+(short4 v) const noexcept { return short4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr short4 operator-(short4 v) const noexcept { return short4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr short4 operator*(short4 v) const noexcept { return short4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr short4 operator/(short4 v) const noexcept { return short4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr short4 operator%(short4 v) const noexcept { return short4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr short4 operator&(short4 v) const noexcept { return short4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr short4 operator|(short4 v) const noexcept { return short4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr short4 operator^(short4 v) const noexcept { return short4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr short4 operator>>(short4 v) const noexcept { return short4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr short4 operator<<(short4 v) const noexcept { return short4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr short4 operator+(int16 n) const noexcept { return short4(x + n, y + n, z + n, w + n); } + constexpr short4 operator-(int16 n) const noexcept { return short4(x - n, y - n, z - n, w - n); } + constexpr short4 operator*(int16 n) const noexcept { return short4(x * n, y * n, z * n, w * n); } + constexpr short4 operator/(int16 n) const noexcept { return short4(x / n, y / n, z / n, w / n); } + constexpr short4 operator%(int16 n) const noexcept { return short4(x % n, y % n, z % n, w % n); } + constexpr short4 operator&(int16 n) const noexcept { return short4(x & n, y & n, z & n, w & n); } + constexpr short4 operator|(int16 n) const noexcept { return short4(x | n, y | n, z | n, w | n); } + constexpr short4 operator^(int16 n) const noexcept { return short4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr short4 operator>>(int16 n) const noexcept { return short4(x >> n, y >> n, z >> n, w >> n); } + constexpr short4 operator<<(int16 n) const noexcept { return short4(x << n, y << n, z << n, w << n); } + constexpr short4 operator-() const noexcept { return short4(-x, -y, -z, -w); } + constexpr short4 operator!() const noexcept { return short4(!x, !y, !z, !w); } + constexpr short4 operator~() const noexcept { return short4(~x, ~y, ~z, ~w); } + short4& operator+=(short4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + short4& operator-=(short4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + short4& operator*=(short4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + short4& operator/=(short4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + short4& operator%=(short4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + short4& operator&=(short4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + short4& operator|=(short4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + short4& operator^=(short4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + short4& operator>>=(short4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + short4& operator<<=(short4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + short4& operator+=(int16 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + short4& operator-=(int16 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + short4& operator*=(int16 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + short4& operator/=(int16 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + short4& operator%=(int16 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + short4& operator&=(int16 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + short4& operator|=(int16 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + short4& operator^=(int16 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + short4& operator>>=(int16 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + short4& operator<<=(int16 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + short4& operator=(int16 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(short4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(short4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr ushort4 operator<(short4 v) const noexcept + { + return ushort4(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0, + z < v.z ? UINT16_MAX : 0, w < v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator>(short4 v) const noexcept + { + return ushort4(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0, + z > v.z ? UINT16_MAX : 0, w > v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator<=(short4 v) const noexcept + { + return ushort4(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0, + z <= v.z ? UINT16_MAX : 0, w <= v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator>=(short4 v) const noexcept + { + return ushort4(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0, + z >= v.z ? UINT16_MAX : 0, w >= v.w ? UINT16_MAX : 0); + } + constexpr bool operator==(int16 n) const noexcept { return *this == short4(n); } + constexpr bool operator!=(int16 n) const noexcept { return *this != short4(n); } + constexpr ushort4 operator<(int16 n) const noexcept { return *this < short4(n); } + constexpr ushort4 operator>(int16 n) const noexcept { return *this > short4(n); } + constexpr ushort4 operator<=(int16 n) const noexcept { return *this <= short4(n); } + constexpr ushort4 operator>=(int16 n) const noexcept { return *this >= short4(n); } + + static const short4 zero, one, minusOne, min, max; +}; + +inline const short4 short4::zero = short4(0); +inline const short4 short4::one = short4(1); +inline const short4 short4::minusOne = short4(-1); +inline const short4 short4::min = short4(INT16_MIN); +inline const short4 short4::max = short4(INT16_MAX); + +//********************************************************************************************************************** +static constexpr short2 operator+(int16 n, short2 v) noexcept { return short2(n) + v; } +static constexpr short2 operator-(int16 n, short2 v) noexcept { return short2(n) - v; } +static constexpr short2 operator*(int16 n, short2 v) noexcept { return short2(n) * v; } +static constexpr short2 operator/(int16 n, short2 v) noexcept { return short2(n) / v; } +static constexpr short2 operator%(int16 n, short2 v) noexcept { return short2(n) % v; } +static constexpr short2 operator&(int16 n, short2 v) noexcept { return short2(n) & v; } +static constexpr short2 operator|(int16 n, short2 v) noexcept { return short2(n) | v; } +static constexpr short2 operator^(int16 n, short2 v) noexcept { return short2(n) ^ v; } +static constexpr short2 operator>>(int16 n, short2 v) noexcept { return short2(n) >> v; } +static constexpr short2 operator<<(int16 n, short2 v) noexcept { return short2(n) << v; } +static constexpr bool operator==(int16 n, short2 v) noexcept { return short2(n) == v; } +static constexpr bool operator!=(int16 n, short2 v) noexcept { return short2(n) != v; } +static constexpr ushort2 operator<(int16 n, short2 v) noexcept { return short2(n) < v; } +static constexpr ushort2 operator>(int16 n, short2 v) noexcept { return short2(n) > v; } +static constexpr ushort2 operator<=(int16 n, short2 v) noexcept { return short2(n) <= v; } +static constexpr ushort2 operator>=(int16 n, short2 v) noexcept { return short2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(short2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort2 equal(short2 a, short2 b) noexcept +{ + return ushort2(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort2 notEqual(short2 a, short2 b) noexcept +{ + return ushort2(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(short2 a, short2 b) noexcept { return *((const int32*)&a) < *((const int32*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr short2 select(ushort2 c, short2 t, short2 f) noexcept +{ + return short2(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr short2 min(short2 a, short2 b) noexcept { return short2(std::min(a.x, b.x), std::min(a.y, b.y)); } +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr short2 max(short2 a, short2 b) noexcept { return short2(std::max(a.x, b.x), std::max(a.y, b.y)); } +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr short2 min(short2 a, short2 b, short2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr short2 max(short2 a, short2 b, short2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr short2 clamp(short2 v, short2 min, short2 max) noexcept +{ + return short2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr short3 operator+(int16 n, short3 v) noexcept { return short3(n) + v; } +static constexpr short3 operator-(int16 n, short3 v) noexcept { return short3(n) - v; } +static constexpr short3 operator*(int16 n, short3 v) noexcept { return short3(n) * v; } +static constexpr short3 operator/(int16 n, short3 v) noexcept { return short3(n) / v; } +static constexpr short3 operator%(int16 n, short3 v) noexcept { return short3(n) % v; } +static constexpr short3 operator&(int16 n, short3 v) noexcept { return short3(n) & v; } +static constexpr short3 operator|(int16 n, short3 v) noexcept { return short3(n) | v; } +static constexpr short3 operator^(int16 n, short3 v) noexcept { return short3(n) ^ v; } +static constexpr short3 operator>>(int16 n, short3 v) noexcept { return short3(n) >> v; } +static constexpr short3 operator<<(int16 n, short3 v) noexcept { return short3(n) << v; } +static constexpr bool operator==(int16 n, short3 v) noexcept { return short3(n) == v; } +static constexpr bool operator!=(int16 n, short3 v) noexcept { return short3(n) != v; } +static constexpr ushort3 operator<(int16 n, short3 v) noexcept { return short3(n) < v; } +static constexpr ushort3 operator>(int16 n, short3 v) noexcept { return short3(n) > v; } +static constexpr ushort3 operator<=(int16 n, short3 v) noexcept { return short3(n) <= v; } +static constexpr ushort3 operator>=(int16 n, short3 v) noexcept { return short3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(short3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort3 equal(short3 a, short3 b) noexcept +{ + return ushort3(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0, a.z == b.z ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort3 notEqual(short3 a, short3 b) noexcept +{ + return ushort3(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0, a.z != b.z ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const short3& a, const short3& b) noexcept { return memcmp(&a, &b, sizeof(short3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr short3 select(ushort3 c, short3 t, short3 f) noexcept +{ + return short3(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y, c.z & 0x8000u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr short3 min(short3 a, short3 b) noexcept +{ + return short3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr short3 max(short3 a, short3 b) noexcept +{ + return short3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr short3 min(short3 a, short3 b, short3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr short3 max(short3 a, short3 b, short3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr short3 clamp(short3 v, short3 min, short3 max) noexcept +{ + return short3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr short4 operator+(int16 n, short4 v) noexcept { return short4(n) + v; } +static constexpr short4 operator-(int16 n, short4 v) noexcept { return short4(n) - v; } +static constexpr short4 operator*(int16 n, short4 v) noexcept { return short4(n) * v; } +static constexpr short4 operator/(int16 n, short4 v) noexcept { return short4(n) / v; } +static constexpr short4 operator%(int16 n, short4 v) noexcept { return short4(n) % v; } +static constexpr short4 operator&(int16 n, short4 v) noexcept { return short4(n) & v; } +static constexpr short4 operator|(int16 n, short4 v) noexcept { return short4(n) | v; } +static constexpr short4 operator^(int16 n, short4 v) noexcept { return short4(n) ^ v; } +static constexpr short4 operator>>(int16 n, short4 v) noexcept { return short4(n) >> v; } +static constexpr short4 operator<<(int16 n, short4 v) noexcept { return short4(n) << v; } +static constexpr bool operator==(int16 n, short4 v) noexcept { return short4(n) == v; } +static constexpr bool operator!=(int16 n, short4 v) noexcept { return short4(n) != v; } +static constexpr ushort4 operator<(int16 n, short4 v) noexcept { return short4(n) < v; } +static constexpr ushort4 operator>(int16 n, short4 v) noexcept { return short4(n) > v; } +static constexpr ushort4 operator<=(int16 n, short4 v) noexcept { return short4(n) <= v; } +static constexpr ushort4 operator>=(int16 n, short4 v) noexcept { return short4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(short4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort4 equal(short4 a, short4 b) noexcept +{ + return ushort4(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0, + a.z == b.z ? UINT16_MAX : 0, a.w == b.w ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort4 notEqual(short4 a, short4 b) noexcept +{ + return ushort4(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0, + a.z != b.z ? UINT16_MAX : 0, a.w != b.w ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const short4& a, const short4& b) noexcept { return *((const int64*)&a) < *((const int64*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr short4 select(ushort4 c, short4 t, short4 f) noexcept +{ + return short4(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y, + c.z & 0x8000u ? t.z : f.z, c.w & 0x8000u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr short4 min(short4 a, short4 b) noexcept +{ + return short4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr short4 max(short4 a, short4 b) noexcept +{ + return short4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr short4 min(short4 a, short4 b, short4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr short4 max(short4 a, short4 b, short4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr short4 clamp(short4 v, short4 min, short4 max) noexcept +{ + return short4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/uint.hpp b/include/math/vector/uint.hpp index a79f042..63009b7 100644 --- a/include/math/vector/uint.hpp +++ b/include/math/vector/uint.hpp @@ -14,18 +14,13 @@ /*********************************************************************************************************************** * @file - * @brief Common unsigned integer vector functions. + * @brief Common unsigned integer 32 bit vector functions. * @details Based on this project: https://github.com/g-truc/glm */ #pragma once -#include "math/types.hpp" - -#include -#include +#include "math/vector/ushort.hpp" #include -#include -#include namespace math { @@ -33,7 +28,7 @@ namespace math using namespace std; /** - * @brief Unsigned integer 2 component vector structure. + * @brief A 2-component vector of 32-bit unsigned integer values. * @details Commonly used to represent: points, positions, etc. */ struct [[nodiscard]] uint2 @@ -42,12 +37,12 @@ struct [[nodiscard]] uint2 uint32 y; /**< Second vector component. */ /** - * @brief Creates a new unsigned integer 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit unsigned integer values. * @param xy target value for all vector components */ constexpr explicit uint2(uint32 xy = 0u) noexcept : x(xy), y(xy) { } /** - * @brief Creates a new unsigned integer 2 component vector structure. + * @brief Creates a new 2-component vector of 32-bit unsigned integer values. * * @param x first vector component value * @param y second vector component value @@ -73,11 +68,6 @@ struct [[nodiscard]] uint2 return ((uint32*)this)[i]; } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator uint32() noexcept { return x; } - //****************************************************************************************************************** constexpr uint2 operator+(uint2 v) const noexcept { return uint2(x + v.x, y + v.y); } constexpr uint2 operator-(uint2 v) const noexcept { return uint2(x - v.x, y - v.y); } @@ -148,14 +138,15 @@ struct [[nodiscard]] uint2 constexpr uint2 operator<=(uint32 n) const noexcept { return *this <= uint2(n); } constexpr uint2 operator>=(uint32 n) const noexcept { return *this >= uint2(n); } - static const uint2 zero, one; + static const uint2 zero, one, max; }; inline const uint2 uint2::zero = uint2(0u); inline const uint2 uint2::one = uint2(1u); +inline const uint2 uint2::max = uint2(UINT32_MAX); /*********************************************************************************************************************** - * @brief Unsigned integer 3 component vector structure. + * @brief A 3-component vector of 32-bit unsigned integer values. * @details Commonly used to represent: points, positions, etc. */ struct [[nodiscard]] uint3 @@ -165,12 +156,12 @@ struct [[nodiscard]] uint3 uint32 z; /**< Third vector component. */ /** - * @brief Creates a new unsigned integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit unsigned integer values. * @param xyz target value for all vector components */ constexpr explicit uint3(uint32 xyz = 0u) noexcept : x(xyz), y(xyz), z(xyz) { } /** - * @brief Creates a new unsigned integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit unsigned integer values. * * @param x first vector component value * @param y second vector component value @@ -178,17 +169,17 @@ struct [[nodiscard]] uint3 */ constexpr uint3(uint32 x, uint32 y, uint32 z) noexcept : x(x), y(y), z(z) { } /** - * @brief Creates a new unsigned integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit unsigned integer values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value */ constexpr uint3(uint2 xy, uint32 z) noexcept : x(xy.x), y(xy.y), z(z) { } /** - * @brief Creates a new unsigned integer 3 component vector structure. + * @brief Creates a new 3-component vector of 32-bit unsigned integer values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value */ constexpr uint3(uint32 x, uint2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } @@ -211,14 +202,7 @@ struct [[nodiscard]] uint3 return ((uint32*)this)[i]; } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ constexpr explicit operator uint2() const noexcept { return uint2(x, y); } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator uint32() const noexcept { return x; } //****************************************************************************************************************** constexpr uint3 operator+(uint3 v) const noexcept { return uint3(x + v.x, y + v.y, z + v.z); } @@ -290,14 +274,15 @@ struct [[nodiscard]] uint3 constexpr uint3 operator<=(uint32 n) const noexcept { return *this <= uint3(n); } constexpr uint3 operator>=(uint32 n) const noexcept { return *this >= uint3(n); } - static const uint3 zero, one; + static const uint3 zero, one, max; }; inline const uint3 uint3::zero = uint3(0u); inline const uint3 uint3::one = uint3(1u); +inline const uint3 uint3::max = uint3(UINT32_MAX); /*********************************************************************************************************************** - * @brief Unsigned integer 4 component vector structure. + * @brief A 4-component vector of 32-bit unsigned integer values. * @details Commonly used to represent: points, positions, etc. */ struct [[nodiscard]] uint4 @@ -308,12 +293,12 @@ struct [[nodiscard]] uint4 uint32 w; /**< Fourth vector component. */ /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * @param xyzw target value for all vector components */ constexpr explicit uint4(uint32 xyzw = 0u) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * * @param x first vector component value * @param y second vector component value @@ -322,48 +307,48 @@ struct [[nodiscard]] uint4 */ constexpr uint4(uint32 x, uint32 y, uint32 z, uint32 w) noexcept : x(x), y(y), z(z), w(w) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * - * @param xy first and second vector components value + * @param xy first and second vector component value * @param z third vector component value * @param w fourth vector component value */ constexpr uint4(uint2 xy, uint32 z, uint32 w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * * @param x first vector component value - * @param yz second and third vector components value + * @param yz second and third vector component value * @param w fourth vector component value */ constexpr uint4(uint32 x, uint2 yz, uint32 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * * @param x first vector component value * @param y second vector component value - * @param zw third and fourth vector components value + * @param zw third and fourth vector component value */ constexpr uint4(uint32 x, uint32 y, uint2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * - * @param xy first and second vector components value - * @param zw third and fourth vector components value + * @param xy first and second vector component value + * @param zw third and fourth vector component value */ constexpr uint4(uint2 xy, uint2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * - * @param xyz first, second and third vector components value + * @param xyz first, second and third vector component value * @param w fourth vector component value */ constexpr uint4(uint3 xyz, uint32 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } /** - * @brief Creates a new unsigned integer 4 component vector structure. + * @brief Creates a new 4-component vector of 32-bit unsigned integer values. * * @param x first vector component value - * @param yzw second, third and fourth vector components value + * @param yzw second, third and fourth vector component value */ constexpr uint4(uint32 x, uint3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } @@ -386,18 +371,8 @@ struct [[nodiscard]] uint4 return ((uint32*)this)[i]; } - /** - * @brief Returns as 3 component unsigned integer vector. (xyz) - */ constexpr explicit operator uint3() const noexcept { return uint3(x, y, z); } - /** - * @brief Returns as 2 component unsigned integer vector. (xy) - */ constexpr explicit operator uint2() const noexcept { return uint2(x, y); } - /** - * @brief Returns first vector component value. (x) - */ - constexpr explicit operator uint32() const noexcept { return x; } //****************************************************************************************************************** constexpr uint4 operator+(uint4 v) const noexcept { return uint4(x + v.x, y + v.y, z + v.z, w + v.w); } @@ -473,11 +448,12 @@ struct [[nodiscard]] uint4 constexpr uint4 operator<=(uint32 n) const noexcept { return *this <= uint4(n); } constexpr uint4 operator>=(uint32 n) const noexcept { return *this >= uint4(n); } - static const uint4 zero, one; + static const uint4 zero, one, max; }; inline const uint4 uint4::zero = uint4(0u); inline const uint4 uint4::one = uint4(1u); +inline const uint4 uint4::max = uint4(UINT32_MAX); //********************************************************************************************************************** static constexpr uint2 operator+(uint32 n, uint2 v) noexcept { return uint2(n) + v; } diff --git a/include/math/vector/ulong.hpp b/include/math/vector/ulong.hpp new file mode 100644 index 0000000..b50260e --- /dev/null +++ b/include/math/vector/ulong.hpp @@ -0,0 +1,878 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common unsigned integer 64 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/vector/uint.hpp" + +namespace math +{ + +using namespace std; + +/** + * @brief A 2-component vector of 64-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ulong2 +{ + uint64 x; /**< First vector component. */ + uint64 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 64-bit unsigned integer values. + * @param xy target value for all vector components + */ + constexpr explicit ulong2(uint64 xy = 0u) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr ulong2(uint64 x, uint64 y) noexcept : x(x), y(y) { } + + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint64& operator[](psize i) noexcept + { + assert(i <= 1); + return ((uint64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint64 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((uint64*)this)[i]; + } + + //****************************************************************************************************************** + constexpr ulong2 operator+(ulong2 v) const noexcept { return ulong2(x + v.x, y + v.y); } + constexpr ulong2 operator-(ulong2 v) const noexcept { return ulong2(x - v.x, y - v.y); } + constexpr ulong2 operator*(ulong2 v) const noexcept { return ulong2(x * v.x, y * v.y); } + constexpr ulong2 operator/(ulong2 v) const noexcept { return ulong2(x / v.x, y / v.y); } + constexpr ulong2 operator%(ulong2 v) const noexcept { return ulong2(x % v.x, y % v.y); } + constexpr ulong2 operator&(ulong2 v) const noexcept { return ulong2(x & v.x, y & v.y); } + constexpr ulong2 operator|(ulong2 v) const noexcept { return ulong2(x | v.x, y | v.y); } + constexpr ulong2 operator^(ulong2 v) const noexcept { return ulong2(x ^ v.x, y ^ v.y); } + constexpr ulong2 operator>>(ulong2 v) const noexcept { return ulong2(x >> v.x, y >> v.y); } + constexpr ulong2 operator<<(ulong2 v) const noexcept { return ulong2(x << v.x, y << v.y); } + constexpr ulong2 operator+(uint64 n) const noexcept { return ulong2(x + n, y + n); } + constexpr ulong2 operator-(uint64 n) const noexcept { return ulong2(x - n, y - n); } + constexpr ulong2 operator*(uint64 n) const noexcept { return ulong2(x * n, y * n); } + constexpr ulong2 operator/(uint64 n) const noexcept { return ulong2(x / n, y / n); } + constexpr ulong2 operator%(uint64 n) const noexcept { return ulong2(x % n, y % n); } + constexpr ulong2 operator&(uint64 n) const noexcept { return ulong2(x & n, y & n); } + constexpr ulong2 operator|(uint64 n) const noexcept { return ulong2(x | n, y | n); } + constexpr ulong2 operator^(uint64 n) const noexcept { return ulong2(x ^ n, y ^ n); } + constexpr ulong2 operator>>(uint64 n) const noexcept { return ulong2(x >> n, y >> n); } + constexpr ulong2 operator<<(uint64 n) const noexcept { return ulong2(x << n, y << n); } + constexpr ulong2 operator-() const noexcept { return ulong2(-x, -y); } + constexpr ulong2 operator!() const noexcept { return ulong2(!x, !y); } + constexpr ulong2 operator~() const noexcept { return ulong2(~x, ~y); } + ulong2& operator+=(ulong2 v) noexcept { x += v.x; y += v.y; return *this; } + ulong2& operator-=(ulong2 v) noexcept { x -= v.x; y -= v.y; return *this; } + ulong2& operator*=(ulong2 v) noexcept { x *= v.x; y *= v.y; return *this; } + ulong2& operator/=(ulong2 v) noexcept { x /= v.x; y /= v.y; return *this; } + ulong2& operator%=(ulong2 v) noexcept { x %= v.x; y %= v.y; return *this; } + ulong2& operator&=(ulong2 v) noexcept { x &= v.x; y &= v.y; return *this; } + ulong2& operator|=(ulong2 v) noexcept { x |= v.x; y |= v.y; return *this; } + ulong2& operator^=(ulong2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + ulong2& operator>>=(ulong2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + ulong2& operator<<=(ulong2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + ulong2& operator+=(uint64 n) noexcept { x += n; y += n; return *this; } + ulong2& operator-=(uint64 n) noexcept { x -= n; y -= n; return *this; } + ulong2& operator*=(uint64 n) noexcept { x *= n; y *= n; return *this; } + ulong2& operator/=(uint64 n) noexcept { x /= n; y /= n; return *this; } + ulong2& operator%=(uint64 n) noexcept { x %= n; y %= n; return *this; } + ulong2& operator&=(uint64 n) noexcept { x &= n; y &= n; return *this; } + ulong2& operator|=(uint64 n) noexcept { x |= n; y |= n; return *this; } + ulong2& operator^=(uint64 n) noexcept { x ^= n; y ^= n; return *this; } + ulong2& operator>>=(uint64 n) noexcept { x >>= n; y >>= n; return *this; } + ulong2& operator<<=(uint64 n) noexcept { x <<= n; y <<= n; return *this; } + ulong2& operator=(uint64 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(ulong2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(ulong2 v) const noexcept { return x != v.x || y != v.y; } + constexpr ulong2 operator<(ulong2 v) const noexcept + { + return ulong2(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator>(ulong2 v) const noexcept + { + return ulong2(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator<=(ulong2 v) const noexcept + { + return ulong2(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0); + } + constexpr ulong2 operator>=(ulong2 v) const noexcept + { + return ulong2(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0); + } + constexpr bool operator==(uint64 n) const noexcept { return *this == ulong2(n); } + constexpr bool operator!=(uint64 n) const noexcept { return *this != ulong2(n); } + constexpr ulong2 operator<(uint64 n) const noexcept { return *this < ulong2(n); } + constexpr ulong2 operator>(uint64 n) const noexcept { return *this > ulong2(n); } + constexpr ulong2 operator<=(uint64 n) const noexcept { return *this <= ulong2(n); } + constexpr ulong2 operator>=(uint64 n) const noexcept { return *this >= ulong2(n); } + + static const ulong2 zero, one; +}; + +inline const ulong2 ulong2::zero = ulong2(0u); +inline const ulong2 ulong2::one = ulong2(1u); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 64-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ulong3 +{ + uint64 x; /**< First vector component. */ + uint64 y; /**< Second vector component. */ + uint64 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 64-bit unsigned integer values. + * @param xyz target value for all vector components + */ + constexpr explicit ulong3(uint64 xyz = 0u) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr ulong3(uint64 x, uint64 y, uint64 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 64-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr ulong3(ulong2 xy, uint64 z) noexcept : x(xy.x), y(xy.y), z(z) { } + /** + * @brief Creates a new 3-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr ulong3(uint64 x, ulong2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint64& operator[](psize i) noexcept + { + assert(i <= 2); + return ((uint64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint64 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((uint64*)this)[i]; + } + + constexpr explicit operator ulong2() const noexcept { return ulong2(x, y); } + + //****************************************************************************************************************** + constexpr ulong3 operator+(ulong3 v) const noexcept { return ulong3(x + v.x, y + v.y, z + v.z); } + constexpr ulong3 operator-(ulong3 v) const noexcept { return ulong3(x - v.x, y - v.y, z - v.z); } + constexpr ulong3 operator*(ulong3 v) const noexcept { return ulong3(x * v.x, y * v.y, z * v.z); } + constexpr ulong3 operator/(ulong3 v) const noexcept { return ulong3(x / v.x, y / v.y, z / v.z); } + constexpr ulong3 operator%(ulong3 v) const noexcept { return ulong3(x % v.x, y % v.y, z % v.z); } + constexpr ulong3 operator&(ulong3 v) const noexcept { return ulong3(x & v.x, y & v.y, z & v.z); } + constexpr ulong3 operator|(ulong3 v) const noexcept { return ulong3(x | v.x, y | v.y, z | v.z); } + constexpr ulong3 operator^(ulong3 v) const noexcept { return ulong3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr ulong3 operator>>(ulong3 v) const noexcept { return ulong3(x >> v.x, y >> v.y, z >> v.z); } + constexpr ulong3 operator<<(ulong3 v) const noexcept { return ulong3(x << v.x, y << v.y, z << v.z); } + constexpr ulong3 operator+(uint64 n) const noexcept { return ulong3(x + n, y + n, z + n); } + constexpr ulong3 operator-(uint64 n) const noexcept { return ulong3(x - n, y - n, z - n); } + constexpr ulong3 operator*(uint64 n) const noexcept { return ulong3(x * n, y * n, z * n); } + constexpr ulong3 operator/(uint64 n) const noexcept { return ulong3(x / n, y / n, z / n); } + constexpr ulong3 operator%(uint64 n) const noexcept { return ulong3(x % n, y % n, z % n); } + constexpr ulong3 operator&(uint64 n) const noexcept { return ulong3(x & n, y & n, z & n); } + constexpr ulong3 operator|(uint64 n) const noexcept { return ulong3(x | n, y | n, z | n); } + constexpr ulong3 operator^(uint64 n) const noexcept { return ulong3(x ^ n, y ^ n, z ^ n); } + constexpr ulong3 operator>>(uint64 n) const noexcept { return ulong3(x >> n, y >> n, z >> n); } + constexpr ulong3 operator<<(uint64 n) const noexcept { return ulong3(x << n, y << n, z << n); } + constexpr ulong3 operator-() const noexcept { return ulong3(-x, -y, -z); } + constexpr ulong3 operator!() const noexcept { return ulong3(!x, !y, !z); } + ulong3 operator~() const noexcept { return ulong3(~x, ~y, ~z); } + ulong3& operator+=(ulong3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + ulong3& operator-=(ulong3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + ulong3& operator*=(ulong3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + ulong3& operator/=(ulong3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + ulong3& operator%=(ulong3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + ulong3& operator&=(ulong3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + ulong3& operator|=(ulong3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + ulong3& operator^=(ulong3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + ulong3& operator>>=(ulong3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + ulong3& operator<<=(ulong3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + ulong3& operator+=(uint64 n) noexcept { x += n; y += n; z += n; return *this; } + ulong3& operator-=(uint64 n) noexcept { x -= n; y -= n; z -= n; return *this; } + ulong3& operator*=(uint64 n) noexcept { x *= n; y *= n; z *= n; return *this; } + ulong3& operator/=(uint64 n) noexcept { x /= n; y /= n; z /= n; return *this; } + ulong3& operator%=(uint64 n) noexcept { x %= n; y %= n; z %= n; return *this; } + ulong3& operator&=(uint64 n) noexcept { x &= n; y &= n; z &= n; return *this; } + ulong3& operator|=(uint64 n) noexcept { x |= n; y |= n; z |= n; return *this; } + ulong3& operator^=(uint64 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + ulong3& operator>>=(uint64 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + ulong3& operator<<=(uint64 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + ulong3& operator=(uint64 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(ulong3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(ulong3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr ulong3 operator<(ulong3 v) const noexcept + { + return ulong3(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0, z < v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator>(ulong3 v) const noexcept + { + return ulong3(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0, z > v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator<=(ulong3 v) const noexcept + { + return ulong3(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0, z <= v.z ? UINT64_MAX : 0); + } + constexpr ulong3 operator>=(ulong3 v) const noexcept + { + return ulong3(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0, z >= v.z ? UINT64_MAX : 0); + } + constexpr bool operator==(uint64 n) const noexcept { return *this == ulong3(n); } + constexpr bool operator!=(uint64 n) const noexcept { return *this != ulong3(n); } + constexpr ulong3 operator<(uint64 n) const noexcept { return *this < ulong3(n); } + constexpr ulong3 operator>(uint64 n) const noexcept { return *this > ulong3(n); } + constexpr ulong3 operator<=(uint64 n) const noexcept { return *this <= ulong3(n); } + constexpr ulong3 operator>=(uint64 n) const noexcept { return *this >= ulong3(n); } + + static const ulong3 zero, one, max; +}; + +inline const ulong3 ulong3::zero = ulong3(0u); +inline const ulong3 ulong3::one = ulong3(1u); +inline const ulong3 ulong3::max = ulong3(UINT64_MAX); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 64-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ulong4 +{ + uint64 x; /**< First vector component. */ + uint64 y; /**< Second vector component. */ + uint64 z; /**< Third vector component. */ + uint64 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit ulong4(uint64 xyzw = 0u) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr ulong4(uint64 x, uint64 y, uint64 z, uint64 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr ulong4(ulong2 xy, uint64 z, uint64 w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr ulong4(uint64 x, ulong2 yz, uint64 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr ulong4(uint64 x, uint64 y, ulong2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr ulong4(ulong2 xy, ulong2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr ulong4(ulong3 xyz, uint64 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 64-bit unsigned integer values. + * + * @param x first vector component value + * @param yzw second, third and fourth vector component value + */ + constexpr ulong4(uint64 x, ulong3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint64& operator[](psize i) noexcept + { + assert(i <= 3); + return ((uint64*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint64 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((uint64*)this)[i]; + } + + constexpr explicit operator ulong3() const noexcept { return ulong3(x, y, z); } + constexpr explicit operator ulong2() const noexcept { return ulong2(x, y); } + + //****************************************************************************************************************** + constexpr ulong4 operator+(ulong4 v) const noexcept { return ulong4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr ulong4 operator-(ulong4 v) const noexcept { return ulong4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr ulong4 operator*(ulong4 v) const noexcept { return ulong4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr ulong4 operator/(ulong4 v) const noexcept { return ulong4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr ulong4 operator%(ulong4 v) const noexcept { return ulong4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr ulong4 operator&(ulong4 v) const noexcept { return ulong4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr ulong4 operator|(ulong4 v) const noexcept { return ulong4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr ulong4 operator^(ulong4 v) const noexcept { return ulong4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr ulong4 operator>>(ulong4 v) const noexcept { return ulong4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr ulong4 operator<<(ulong4 v) const noexcept { return ulong4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr ulong4 operator+(uint64 n) const noexcept { return ulong4(x + n, y + n, z + n, w + n); } + constexpr ulong4 operator-(uint64 n) const noexcept { return ulong4(x - n, y - n, z - n, w - n); } + constexpr ulong4 operator*(uint64 n) const noexcept { return ulong4(x * n, y * n, z * n, w * n); } + constexpr ulong4 operator/(uint64 n) const noexcept { return ulong4(x / n, y / n, z / n, w / n); } + constexpr ulong4 operator%(uint64 n) const noexcept { return ulong4(x % n, y % n, z % n, w % n); } + constexpr ulong4 operator&(uint64 n) const noexcept { return ulong4(x & n, y & n, z & n, w & n); } + constexpr ulong4 operator|(uint64 n) const noexcept { return ulong4(x | n, y | n, z | n, w | n); } + constexpr ulong4 operator^(uint64 n) const noexcept { return ulong4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr ulong4 operator>>(uint64 n) const noexcept { return ulong4(x >> n, y >> n, z >> n, w >> n); } + constexpr ulong4 operator<<(uint64 n) const noexcept { return ulong4(x << n, y << n, z << n, w << n); } + constexpr ulong4 operator-() const noexcept { return ulong4(-x, -y, -z, -w); } + constexpr ulong4 operator!() const noexcept { return ulong4(!x, !y, !z, !w); } + constexpr ulong4 operator~() const noexcept { return ulong4(~x, ~y, ~z, ~w); } + ulong4& operator+=(ulong4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + ulong4& operator-=(ulong4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + ulong4& operator*=(ulong4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + ulong4& operator/=(ulong4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + ulong4& operator%=(ulong4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + ulong4& operator&=(ulong4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + ulong4& operator|=(ulong4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + ulong4& operator^=(ulong4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + ulong4& operator>>=(ulong4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + ulong4& operator<<=(ulong4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + ulong4& operator+=(uint64 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + ulong4& operator-=(uint64 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + ulong4& operator*=(uint64 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + ulong4& operator/=(uint64 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + ulong4& operator%=(uint64 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + ulong4& operator&=(uint64 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + ulong4& operator|=(uint64 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + ulong4& operator^=(uint64 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + ulong4& operator>>=(uint64 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + ulong4& operator<<=(uint64 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + ulong4& operator=(uint64 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(ulong4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(ulong4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr ulong4 operator<(ulong4 v) const noexcept + { + return ulong4(x < v.x ? UINT64_MAX : 0, y < v.y ? UINT64_MAX : 0, + z < v.z ? UINT64_MAX : 0, w < v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator>(ulong4 v) const noexcept + { + return ulong4(x > v.x ? UINT64_MAX : 0, y > v.y ? UINT64_MAX : 0, + z > v.z ? UINT64_MAX : 0, w > v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator<=(ulong4 v) const noexcept + { + return ulong4(x <= v.x ? UINT64_MAX : 0, y <= v.y ? UINT64_MAX : 0, + z <= v.z ? UINT64_MAX : 0, w <= v.w ? UINT64_MAX : 0); + } + constexpr ulong4 operator>=(ulong4 v) const noexcept + { + return ulong4(x >= v.x ? UINT64_MAX : 0, y >= v.y ? UINT64_MAX : 0, + z >= v.z ? UINT64_MAX : 0, w >= v.w ? UINT64_MAX : 0); + } + constexpr bool operator==(uint64 n) const noexcept { return *this == ulong4(n); } + constexpr bool operator!=(uint64 n) const noexcept { return *this != ulong4(n); } + constexpr ulong4 operator<(uint64 n) const noexcept { return *this < ulong4(n); } + constexpr ulong4 operator>(uint64 n) const noexcept { return *this > ulong4(n); } + constexpr ulong4 operator<=(uint64 n) const noexcept { return *this <= ulong4(n); } + constexpr ulong4 operator>=(uint64 n) const noexcept { return *this >= ulong4(n); } + + static const ulong4 zero, one, max; +}; + +inline const ulong4 ulong4::zero = ulong4(0u); +inline const ulong4 ulong4::one = ulong4(1u); +inline const ulong4 ulong4::max = ulong4(UINT64_MAX); + +//********************************************************************************************************************** +static constexpr ulong2 operator+(uint64 n, ulong2 v) noexcept { return ulong2(n) + v; } +static constexpr ulong2 operator-(uint64 n, ulong2 v) noexcept { return ulong2(n) - v; } +static constexpr ulong2 operator*(uint64 n, ulong2 v) noexcept { return ulong2(n) * v; } +static constexpr ulong2 operator/(uint64 n, ulong2 v) noexcept { return ulong2(n) / v; } +static constexpr ulong2 operator%(uint64 n, ulong2 v) noexcept { return ulong2(n) % v; } +static constexpr ulong2 operator&(uint64 n, ulong2 v) noexcept { return ulong2(n) & v; } +static constexpr ulong2 operator|(uint64 n, ulong2 v) noexcept { return ulong2(n) | v; } +static constexpr ulong2 operator^(uint64 n, ulong2 v) noexcept { return ulong2(n) ^ v; } +static constexpr ulong2 operator>>(uint64 n, ulong2 v) noexcept { return ulong2(n) >> v; } +static constexpr ulong2 operator<<(uint64 n, ulong2 v) noexcept { return ulong2(n) << v; } +static constexpr bool operator==(uint64 n, ulong2 v) noexcept { return ulong2(n) == v; } +static constexpr bool operator!=(uint64 n, ulong2 v) noexcept { return ulong2(n) != v; } +static constexpr ulong2 operator<(uint64 n, ulong2 v) noexcept { return ulong2(n) < v; } +static constexpr ulong2 operator>(uint64 n, ulong2 v) noexcept { return ulong2(n) > v; } +static constexpr ulong2 operator<=(uint64 n, ulong2 v) noexcept { return ulong2(n) <= v; } +static constexpr ulong2 operator>=(uint64 n, ulong2 v) noexcept { return ulong2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ulong2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (2bits) + */ +static constexpr uint64 getTrues(ulong2 v) noexcept +{ + return (v.x >> 63u) | ((v.y >> 63u) << 1u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ulong2 v) noexcept { return (v.x & v.y) == UINT64_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ulong2 v) noexcept { return (v.x | v.y) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ulong2 v) noexcept { return v.x | v.y; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ulong2 v) noexcept { return (v.x & v.y) != UINT64_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong2 equal(ulong2 a, ulong2 b) noexcept +{ + return ulong2(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong2 notEqual(ulong2 a, ulong2 b) noexcept +{ + return ulong2(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(ulong2 a, ulong2 b) noexcept { return memcmp(&a, &b, sizeof(ulong2)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr ulong2 select(ulong2 c, ulong2 t, ulong2 f) noexcept +{ + return ulong2(c.x & 0x8000000000000000u ? t.x : f.x, c.y & 0x8000000000000000u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ulong2 min(ulong2 a, ulong2 b) noexcept +{ + return ulong2(std::min(a.x, b.x), std::min(a.y, b.y)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ulong2 max(ulong2 a, ulong2 b) noexcept +{ + return ulong2(std::max(a.x, b.x), std::max(a.y, b.y)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ulong2 min(ulong2 a, ulong2 b, ulong2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ulong2 max(ulong2 a, ulong2 b, ulong2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ulong2 clamp(ulong2 v, ulong2 min, ulong2 max) noexcept +{ + return ulong2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr ulong3 operator+(uint64 n, ulong3 v) noexcept { return ulong3(n) + v; } +static constexpr ulong3 operator-(uint64 n, ulong3 v) noexcept { return ulong3(n) - v; } +static constexpr ulong3 operator*(uint64 n, ulong3 v) noexcept { return ulong3(n) * v; } +static constexpr ulong3 operator/(uint64 n, ulong3 v) noexcept { return ulong3(n) / v; } +static constexpr ulong3 operator%(uint64 n, ulong3 v) noexcept { return ulong3(n) % v; } +static constexpr ulong3 operator&(uint64 n, ulong3 v) noexcept { return ulong3(n) & v; } +static constexpr ulong3 operator|(uint64 n, ulong3 v) noexcept { return ulong3(n) | v; } +static constexpr ulong3 operator^(uint64 n, ulong3 v) noexcept { return ulong3(n) ^ v; } +static constexpr ulong3 operator>>(uint64 n, ulong3 v) noexcept { return ulong3(n) >> v; } +static constexpr ulong3 operator<<(uint64 n, ulong3 v) noexcept { return ulong3(n) << v; } +static constexpr bool operator==(uint64 n, ulong3 v) noexcept { return ulong3(n) == v; } +static constexpr bool operator!=(uint64 n, ulong3 v) noexcept { return ulong3(n) != v; } +static constexpr ulong3 operator<(uint64 n, ulong3 v) noexcept { return ulong3(n) < v; } +static constexpr ulong3 operator>(uint64 n, ulong3 v) noexcept { return ulong3(n) > v; } +static constexpr ulong3 operator<=(uint64 n, ulong3 v) noexcept { return ulong3(n) <= v; } +static constexpr ulong3 operator>=(uint64 n, ulong3 v) noexcept { return ulong3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ulong3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (3bits) + */ +static constexpr uint64 getTrues(ulong3 v) noexcept +{ + return (v.x >> 63u) | ((v.y >> 63u) << 1u) | ((v.z >> 63u) << 2u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ulong3 v) noexcept { return (v.x & v.y & v.z) == UINT64_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ulong3 v) noexcept { return (v.x | v.y | v.z) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ulong3 v) noexcept { return v.x | v.y | v.z; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ulong3 v) noexcept { return (v.x & v.y & v.z) != UINT64_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong3 equal(ulong3 a, ulong3 b) noexcept +{ + return ulong3(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0, a.z == b.z ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong3 notEqual(ulong3 a, ulong3 b) noexcept +{ + return ulong3(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0, a.z != b.z ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const ulong3& a, const ulong3& b) noexcept { return memcmp(&a, &b, sizeof(ulong3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr ulong3 select(ulong3 c, ulong3 t, ulong3 f) noexcept +{ + return ulong3(c.x & 0x8000000000000000u ? t.x : f.x, + c.y & 0x8000000000000000u ? t.y : f.y, c.z & 0x8000000000000000u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ulong3 min(ulong3 a, ulong3 b) noexcept +{ + return ulong3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ulong3 max(ulong3 a, ulong3 b) noexcept +{ + return ulong3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ulong3 min(ulong3 a, ulong3 b, ulong3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ulong3 max(ulong3 a, ulong3 b, ulong3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ulong3 clamp(ulong3 v, ulong3 min, ulong3 max) noexcept +{ + return ulong3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr ulong4 operator+(uint64 n, const ulong4& v) noexcept { return ulong4(n) + v; } +static constexpr ulong4 operator-(uint64 n, const ulong4& v) noexcept { return ulong4(n) - v; } +static constexpr ulong4 operator*(uint64 n, const ulong4& v) noexcept { return ulong4(n) * v; } +static constexpr ulong4 operator/(uint64 n, const ulong4& v) noexcept { return ulong4(n) / v; } +static constexpr ulong4 operator%(uint64 n, const ulong4& v) noexcept { return ulong4(n) % v; } +static constexpr ulong4 operator&(uint64 n, const ulong4& v) noexcept { return ulong4(n) & v; } +static constexpr ulong4 operator|(uint64 n, const ulong4& v) noexcept { return ulong4(n) | v; } +static constexpr ulong4 operator^(uint64 n, const ulong4& v) noexcept { return ulong4(n) ^ v; } +static constexpr ulong4 operator>>(uint64 n, const ulong4& v) noexcept { return ulong4(n) >> v; } +static constexpr ulong4 operator<<(uint64 n, const ulong4& v) noexcept { return ulong4(n) << v; } +static constexpr bool operator==(uint64 n, const ulong4& v) noexcept { return ulong4(n) == v; } +static constexpr bool operator!=(uint64 n, const ulong4& v) noexcept { return ulong4(n) != v; } +static constexpr ulong4 operator<(uint64 n, const ulong4& v) noexcept { return ulong4(n) < v; } +static constexpr ulong4 operator>(uint64 n, const ulong4& v) noexcept { return ulong4(n) > v; } +static constexpr ulong4 operator<=(uint64 n, const ulong4& v) noexcept { return ulong4(n) <= v; } +static constexpr ulong4 operator>=(uint64 n, const ulong4& v) noexcept { return ulong4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ulong4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (4bits) + */ +static constexpr uint64 getTrues(ulong4 v) noexcept +{ + return (v.x >> 63u) | ((v.y >> 63u) << 1u) | ((v.z >> 63u) << 2u) | ((v.w >> 63u) << 3u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ulong4 v) noexcept { return (v.x & v.y & v.z & v.w) == UINT64_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ulong4 v) noexcept { return (v.x | v.y | v.z | v.w) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ulong4 v) noexcept { return v.x | v.y | v.z | v.w; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ulong4 v) noexcept { return (v.x & v.y & v.z & v.w) != UINT64_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong4 equal(ulong4 a, ulong4 b) noexcept +{ + return ulong4(a.x == b.x ? UINT64_MAX : 0, a.y == b.y ? UINT64_MAX : 0, + a.z == b.z ? UINT64_MAX : 0, a.w == b.w ? UINT64_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ulong4 notEqual(ulong4 a, ulong4 b) noexcept +{ + return ulong4(a.x != b.x ? UINT64_MAX : 0, a.y != b.y ? UINT64_MAX : 0, + a.z != b.z ? UINT64_MAX : 0, a.w != b.w ? UINT64_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const ulong4& a, const ulong4& b) noexcept { return memcmp(&a, &b, sizeof(ulong4)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr ulong4 select(ulong4 c, ulong4 t, ulong4 f) noexcept +{ + return ulong4(c.x & 0x8000000000000000u ? t.x : f.x, c.y & 0x8000000000000000u ? t.y : f.y, + c.z & 0x8000000000000000u ? t.z : f.z, c.w & 0x8000000000000000u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ulong4 min(ulong4 a, ulong4 b) noexcept +{ + return ulong4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ulong4 max(ulong4 a, ulong4 b) noexcept +{ + return ulong4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ulong4 min(ulong4 a, ulong4 b, ulong4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ulong4 max(ulong4 a, ulong4 b, ulong4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ulong4 clamp(ulong4 v, ulong4 min, ulong4 max) noexcept +{ + return ulong4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/include/math/vector/ushort.hpp b/include/math/vector/ushort.hpp new file mode 100644 index 0000000..1e44b99 --- /dev/null +++ b/include/math/vector/ushort.hpp @@ -0,0 +1,896 @@ +// Copyright 2022-2026 Nikita Fediuchin. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/*********************************************************************************************************************** + * @file + * @brief Common unsigned integer 16 bit vector functions. + * @details Based on this project: https://github.com/g-truc/glm + */ + +#pragma once +#include "math/vector/byte.hpp" + +namespace math +{ + +using namespace std; + +/** + * @brief A 2-component vector of 16-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ushort2 +{ + uint16 x; /**< First vector component. */ + uint16 y; /**< Second vector component. */ + + /** + * @brief Creates a new 2-component vector of 16-bit unsigned integer values. + * @param xy target value for all vector components + */ + constexpr explicit ushort2(uint16 xy = 0u) noexcept : x(xy), y(xy) { } + /** + * @brief Creates a new 2-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + */ + constexpr ushort2(uint16 x, uint16 y) noexcept : x(x), y(y) { } + /** + * @brief Creates a new 2-component vector of 16-bit unsigned integer values. + * @param xy first and second vector component value + */ + constexpr ushort2(byte2 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } + + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint16& operator[](psize i) noexcept + { + assert(i <= 1); + return ((uint16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint16 operator[](psize i) const noexcept + { + assert(i <= 1); + return ((uint16*)this)[i]; + } + + //****************************************************************************************************************** + constexpr ushort2 operator+(ushort2 v) const noexcept { return ushort2(x + v.x, y + v.y); } + constexpr ushort2 operator-(ushort2 v) const noexcept { return ushort2(x - v.x, y - v.y); } + constexpr ushort2 operator*(ushort2 v) const noexcept { return ushort2(x * v.x, y * v.y); } + constexpr ushort2 operator/(ushort2 v) const noexcept { return ushort2(x / v.x, y / v.y); } + constexpr ushort2 operator%(ushort2 v) const noexcept { return ushort2(x % v.x, y % v.y); } + constexpr ushort2 operator&(ushort2 v) const noexcept { return ushort2(x & v.x, y & v.y); } + constexpr ushort2 operator|(ushort2 v) const noexcept { return ushort2(x | v.x, y | v.y); } + constexpr ushort2 operator^(ushort2 v) const noexcept { return ushort2(x ^ v.x, y ^ v.y); } + constexpr ushort2 operator>>(ushort2 v) const noexcept { return ushort2(x >> v.x, y >> v.y); } + constexpr ushort2 operator<<(ushort2 v) const noexcept { return ushort2(x << v.x, y << v.y); } + constexpr ushort2 operator+(uint16 n) const noexcept { return ushort2(x + n, y + n); } + constexpr ushort2 operator-(uint16 n) const noexcept { return ushort2(x - n, y - n); } + constexpr ushort2 operator*(uint16 n) const noexcept { return ushort2(x * n, y * n); } + constexpr ushort2 operator/(uint16 n) const noexcept { return ushort2(x / n, y / n); } + constexpr ushort2 operator%(uint16 n) const noexcept { return ushort2(x % n, y % n); } + constexpr ushort2 operator&(uint16 n) const noexcept { return ushort2(x & n, y & n); } + constexpr ushort2 operator|(uint16 n) const noexcept { return ushort2(x | n, y | n); } + constexpr ushort2 operator^(uint16 n) const noexcept { return ushort2(x ^ n, y ^ n); } + constexpr ushort2 operator>>(uint16 n) const noexcept { return ushort2(x >> n, y >> n); } + constexpr ushort2 operator<<(uint16 n) const noexcept { return ushort2(x << n, y << n); } + constexpr ushort2 operator-() const noexcept { return ushort2(-x, -y); } + constexpr ushort2 operator!() const noexcept { return ushort2(!x, !y); } + constexpr ushort2 operator~() const noexcept { return ushort2(~x, ~y); } + ushort2& operator+=(ushort2 v) noexcept { x += v.x; y += v.y; return *this; } + ushort2& operator-=(ushort2 v) noexcept { x -= v.x; y -= v.y; return *this; } + ushort2& operator*=(ushort2 v) noexcept { x *= v.x; y *= v.y; return *this; } + ushort2& operator/=(ushort2 v) noexcept { x /= v.x; y /= v.y; return *this; } + ushort2& operator%=(ushort2 v) noexcept { x %= v.x; y %= v.y; return *this; } + ushort2& operator&=(ushort2 v) noexcept { x &= v.x; y &= v.y; return *this; } + ushort2& operator|=(ushort2 v) noexcept { x |= v.x; y |= v.y; return *this; } + ushort2& operator^=(ushort2 v) noexcept { x ^= v.x; y ^= v.y; return *this; } + ushort2& operator>>=(ushort2 v) noexcept { x >>= v.x; y >>= v.y; return *this; } + ushort2& operator<<=(ushort2 v) noexcept { x <<= v.x; y <<= v.y; return *this; } + ushort2& operator+=(uint16 n) noexcept { x += n; y += n; return *this; } + ushort2& operator-=(uint16 n) noexcept { x -= n; y -= n; return *this; } + ushort2& operator*=(uint16 n) noexcept { x *= n; y *= n; return *this; } + ushort2& operator/=(uint16 n) noexcept { x /= n; y /= n; return *this; } + ushort2& operator%=(uint16 n) noexcept { x %= n; y %= n; return *this; } + ushort2& operator&=(uint16 n) noexcept { x &= n; y &= n; return *this; } + ushort2& operator|=(uint16 n) noexcept { x |= n; y |= n; return *this; } + ushort2& operator^=(uint16 n) noexcept { x ^= n; y ^= n; return *this; } + ushort2& operator>>=(uint16 n) noexcept { x >>= n; y >>= n; return *this; } + ushort2& operator<<=(uint16 n) noexcept { x <<= n; y <<= n; return *this; } + ushort2& operator=(uint16 n) noexcept { x = n; y = n; return *this; } + constexpr bool operator==(ushort2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(ushort2 v) const noexcept { return x != v.x || y != v.y; } + constexpr ushort2 operator<(ushort2 v) const noexcept + { + return ushort2(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator>(ushort2 v) const noexcept + { + return ushort2(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator<=(ushort2 v) const noexcept + { + return ushort2(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0); + } + constexpr ushort2 operator>=(ushort2 v) const noexcept + { + return ushort2(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0); + } + constexpr bool operator==(uint16 n) const noexcept { return *this == ushort2(n); } + constexpr bool operator!=(uint16 n) const noexcept { return *this != ushort2(n); } + constexpr ushort2 operator<(uint16 n) const noexcept { return *this < ushort2(n); } + constexpr ushort2 operator>(uint16 n) const noexcept { return *this > ushort2(n); } + constexpr ushort2 operator<=(uint16 n) const noexcept { return *this <= ushort2(n); } + constexpr ushort2 operator>=(uint16 n) const noexcept { return *this >= ushort2(n); } + + static const ushort2 zero, one, max; +}; + +inline const ushort2 ushort2::zero = ushort2(0u); +inline const ushort2 ushort2::one = ushort2(1u); +inline const ushort2 ushort2::max = ushort2(UINT16_MAX); + +/*********************************************************************************************************************** + * @brief A 3-component vector of 16-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ushort3 +{ + uint16 x; /**< First vector component. */ + uint16 y; /**< Second vector component. */ + uint16 z; /**< Third vector component. */ + + /** + * @brief Creates a new 3-component vector of 16-bit unsigned integer values. + * @param xyz target value for all vector components + */ + constexpr explicit ushort3(uint16 xyz = 0u) noexcept : x(xyz), y(xyz), z(xyz) { } + /** + * @brief Creates a new 3-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + */ + constexpr ushort3(uint16 x, uint16 y, uint16 z) noexcept : x(x), y(y), z(z) { } + /** + * @brief Creates a new 3-component vector of 16-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + */ + constexpr ushort3(ushort2 xy, uint16 z) noexcept : x(xy.x), y(xy.y), z(z) { } + /** + * @brief Creates a new 3-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + */ + constexpr ushort3(uint16 x, ushort2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + /** + * @brief Creates a new 3-component vector of 16-bit unsigned integer values. + * @param xyz first, second and third vector component value + */ + constexpr ushort3(byte3 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint16& operator[](psize i) noexcept + { + assert(i <= 2); + return ((uint16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint16 operator[](psize i) const noexcept + { + assert(i <= 2); + return ((uint16*)this)[i]; + } + + constexpr explicit operator ushort2() const noexcept { return ushort2(x, y); } + + //****************************************************************************************************************** + constexpr ushort3 operator+(ushort3 v) const noexcept { return ushort3(x + v.x, y + v.y, z + v.z); } + constexpr ushort3 operator-(ushort3 v) const noexcept { return ushort3(x - v.x, y - v.y, z - v.z); } + constexpr ushort3 operator*(ushort3 v) const noexcept { return ushort3(x * v.x, y * v.y, z * v.z); } + constexpr ushort3 operator/(ushort3 v) const noexcept { return ushort3(x / v.x, y / v.y, z / v.z); } + constexpr ushort3 operator%(ushort3 v) const noexcept { return ushort3(x % v.x, y % v.y, z % v.z); } + constexpr ushort3 operator&(ushort3 v) const noexcept { return ushort3(x & v.x, y & v.y, z & v.z); } + constexpr ushort3 operator|(ushort3 v) const noexcept { return ushort3(x | v.x, y | v.y, z | v.z); } + constexpr ushort3 operator^(ushort3 v) const noexcept { return ushort3(x ^ v.x, y ^ v.y, z ^ v.z); } + constexpr ushort3 operator>>(ushort3 v) const noexcept { return ushort3(x >> v.x, y >> v.y, z >> v.z); } + constexpr ushort3 operator<<(ushort3 v) const noexcept { return ushort3(x << v.x, y << v.y, z << v.z); } + constexpr ushort3 operator+(uint16 n) const noexcept { return ushort3(x + n, y + n, z + n); } + constexpr ushort3 operator-(uint16 n) const noexcept { return ushort3(x - n, y - n, z - n); } + constexpr ushort3 operator*(uint16 n) const noexcept { return ushort3(x * n, y * n, z * n); } + constexpr ushort3 operator/(uint16 n) const noexcept { return ushort3(x / n, y / n, z / n); } + constexpr ushort3 operator%(uint16 n) const noexcept { return ushort3(x % n, y % n, z % n); } + constexpr ushort3 operator&(uint16 n) const noexcept { return ushort3(x & n, y & n, z & n); } + constexpr ushort3 operator|(uint16 n) const noexcept { return ushort3(x | n, y | n, z | n); } + constexpr ushort3 operator^(uint16 n) const noexcept { return ushort3(x ^ n, y ^ n, z ^ n); } + constexpr ushort3 operator>>(uint16 n) const noexcept { return ushort3(x >> n, y >> n, z >> n); } + constexpr ushort3 operator<<(uint16 n) const noexcept { return ushort3(x << n, y << n, z << n); } + constexpr ushort3 operator-() const noexcept { return ushort3(-x, -y, -z); } + constexpr ushort3 operator!() const noexcept { return ushort3(!x, !y, !z); } + ushort3 operator~() const noexcept { return ushort3(~x, ~y, ~z); } + ushort3& operator+=(ushort3 v) noexcept { x += v.x; y += v.y; z += v.z; return *this; } + ushort3& operator-=(ushort3 v) noexcept { x -= v.x; y -= v.y; z -= v.z; return *this; } + ushort3& operator*=(ushort3 v) noexcept { x *= v.x; y *= v.y; z *= v.z; return *this; } + ushort3& operator/=(ushort3 v) noexcept { x /= v.x; y /= v.y; z /= v.z; return *this; } + ushort3& operator%=(ushort3 v) noexcept { x %= v.x; y %= v.y; z %= v.z; return *this; } + ushort3& operator&=(ushort3 v) noexcept { x &= v.x; y &= v.y; z &= v.z; return *this; } + ushort3& operator|=(ushort3 v) noexcept { x |= v.x; y |= v.y; z |= v.z; return *this; } + ushort3& operator^=(ushort3 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; return *this; } + ushort3& operator>>=(ushort3 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; return *this; } + ushort3& operator<<=(ushort3 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; return *this; } + ushort3& operator+=(uint16 n) noexcept { x += n; y += n; z += n; return *this; } + ushort3& operator-=(uint16 n) noexcept { x -= n; y -= n; z -= n; return *this; } + ushort3& operator*=(uint16 n) noexcept { x *= n; y *= n; z *= n; return *this; } + ushort3& operator/=(uint16 n) noexcept { x /= n; y /= n; z /= n; return *this; } + ushort3& operator%=(uint16 n) noexcept { x %= n; y %= n; z %= n; return *this; } + ushort3& operator&=(uint16 n) noexcept { x &= n; y &= n; z &= n; return *this; } + ushort3& operator|=(uint16 n) noexcept { x |= n; y |= n; z |= n; return *this; } + ushort3& operator^=(uint16 n) noexcept { x ^= n; y ^= n; z ^= n; return *this; } + ushort3& operator>>=(uint16 n) noexcept { x >>= n; y >>= n; z >>= n; return *this; } + ushort3& operator<<=(uint16 n) noexcept { x <<= n; y <<= n; z <<= n; return *this; } + ushort3& operator=(uint16 n) noexcept { x = n; y = n; z = n; return *this; } + constexpr bool operator==(ushort3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(ushort3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + constexpr ushort3 operator<(ushort3 v) const noexcept + { + return ushort3(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0, z < v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator>(ushort3 v) const noexcept + { + return ushort3(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0, z > v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator<=(ushort3 v) const noexcept + { + return ushort3(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0, z <= v.z ? UINT16_MAX : 0); + } + constexpr ushort3 operator>=(ushort3 v) const noexcept + { + return ushort3(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0, z >= v.z ? UINT16_MAX : 0); + } + constexpr bool operator==(uint16 n) const noexcept { return *this == ushort3(n); } + constexpr bool operator!=(uint16 n) const noexcept { return *this != ushort3(n); } + constexpr ushort3 operator<(uint16 n) const noexcept { return *this < ushort3(n); } + constexpr ushort3 operator>(uint16 n) const noexcept { return *this > ushort3(n); } + constexpr ushort3 operator<=(uint16 n) const noexcept { return *this <= ushort3(n); } + constexpr ushort3 operator>=(uint16 n) const noexcept { return *this >= ushort3(n); } + + static const ushort3 zero, one, max; +}; + +inline const ushort3 ushort3::zero = ushort3(0u); +inline const ushort3 ushort3::one = ushort3(1u); +inline const ushort3 ushort3::max = ushort3(UINT16_MAX); + +/*********************************************************************************************************************** + * @brief A 4-component vector of 16-bit unsigned integer values. + * @details Commonly used to represent: points, positions, etc. + */ +struct [[nodiscard]] ushort4 +{ + uint16 x; /**< First vector component. */ + uint16 y; /**< Second vector component. */ + uint16 z; /**< Third vector component. */ + uint16 w; /**< Fourth vector component. */ + + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * @param xyzw target value for all vector components + */ + constexpr explicit ushort4(uint16 xyzw = 0u) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr ushort4(uint16 x, uint16 y, uint16 z, uint16 w) noexcept : x(x), y(y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param z third vector component value + * @param w fourth vector component value + */ + constexpr ushort4(ushort2 xy, uint16 z, uint16 w) noexcept : x(xy.x), y(xy.y), z(z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param yz second and third vector component value + * @param w fourth vector component value + */ + constexpr ushort4(uint16 x, ushort2 yz, uint16 w) noexcept : x(x), y(yz.x), z(yz.y), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param y second vector component value + * @param zw third and fourth vector component value + */ + constexpr ushort4(uint16 x, uint16 y, ushort2 zw) noexcept : x(x), y(y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param xy first and second vector component value + * @param zw third and fourth vector component value + */ + constexpr ushort4(ushort2 xy, ushort2 zw) noexcept : x(xy.x), y(xy.y), z(zw.x), w(zw.y) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param xyz first, second and third vector component value + * @param w fourth vector component value + */ + constexpr ushort4(ushort3 xyz, uint16 w) noexcept : x(xyz.x), y(xyz.y), z(xyz.z), w(w) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * + * @param x first vector component value + * @param yzw second, third and fourth vector component value + */ + constexpr ushort4(uint16 x, ushort3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + /** + * @brief Creates a new 4-component vector of 16-bit unsigned integer values. + * @param xyzw first, second, third and fourth vector component value + */ + constexpr ushort4(byte4 xyzw) noexcept : x((uint16)xyzw.x), y((uint16)xyzw.y), z((uint16)xyzw.z), w((uint16)xyzw.w) { } + + /******************************************************************************************************************* + * @brief Returns vector component by index. + * @param i target component index + */ + uint16& operator[](psize i) noexcept + { + assert(i <= 3); + return ((uint16*)this)[i]; + } + /** + * @brief Returns vector component by index. + * @param i target component index + */ + uint16 operator[](psize i) const noexcept + { + assert(i <= 3); + return ((uint16*)this)[i]; + } + + constexpr explicit operator ushort3() const noexcept { return ushort3(x, y, z); } + constexpr explicit operator ushort2() const noexcept { return ushort2(x, y); } + + //****************************************************************************************************************** + constexpr ushort4 operator+(ushort4 v) const noexcept { return ushort4(x + v.x, y + v.y, z + v.z, w + v.w); } + constexpr ushort4 operator-(ushort4 v) const noexcept { return ushort4(x - v.x, y - v.y, z - v.z, w - v.w); } + constexpr ushort4 operator*(ushort4 v) const noexcept { return ushort4(x * v.x, y * v.y, z * v.z, w * v.w); } + constexpr ushort4 operator/(ushort4 v) const noexcept { return ushort4(x / v.x, y / v.y, z / v.z, w / v.w); } + constexpr ushort4 operator%(ushort4 v) const noexcept { return ushort4(x % v.x, y % v.y, z % v.z, w % v.w); } + constexpr ushort4 operator&(ushort4 v) const noexcept { return ushort4(x & v.x, y & v.y, z & v.z, w & v.w); } + constexpr ushort4 operator|(ushort4 v) const noexcept { return ushort4(x | v.x, y | v.y, z | v.z, w | v.w); } + constexpr ushort4 operator^(ushort4 v) const noexcept { return ushort4(x ^ v.x, y ^ v.y, z ^ v.z, w ^ v.w); } + constexpr ushort4 operator>>(ushort4 v) const noexcept { return ushort4(x >> v.x, y >> v.y, z >> v.z, w >> v.w); } + constexpr ushort4 operator<<(ushort4 v) const noexcept { return ushort4(x << v.x, y << v.y, z << v.z, w << v.w); } + constexpr ushort4 operator+(uint16 n) const noexcept { return ushort4(x + n, y + n, z + n, w + n); } + constexpr ushort4 operator-(uint16 n) const noexcept { return ushort4(x - n, y - n, z - n, w - n); } + constexpr ushort4 operator*(uint16 n) const noexcept { return ushort4(x * n, y * n, z * n, w * n); } + constexpr ushort4 operator/(uint16 n) const noexcept { return ushort4(x / n, y / n, z / n, w / n); } + constexpr ushort4 operator%(uint16 n) const noexcept { return ushort4(x % n, y % n, z % n, w % n); } + constexpr ushort4 operator&(uint16 n) const noexcept { return ushort4(x & n, y & n, z & n, w & n); } + constexpr ushort4 operator|(uint16 n) const noexcept { return ushort4(x | n, y | n, z | n, w | n); } + constexpr ushort4 operator^(uint16 n) const noexcept { return ushort4(x ^ n, y ^ n, z ^ n, w ^ n); } + constexpr ushort4 operator>>(uint16 n) const noexcept { return ushort4(x >> n, y >> n, z >> n, w >> n); } + constexpr ushort4 operator<<(uint16 n) const noexcept { return ushort4(x << n, y << n, z << n, w << n); } + constexpr ushort4 operator-() const noexcept { return ushort4(-x, -y, -z, -w); } + constexpr ushort4 operator!() const noexcept { return ushort4(!x, !y, !z, !w); } + constexpr ushort4 operator~() const noexcept { return ushort4(~x, ~y, ~z, ~w); } + ushort4& operator+=(ushort4 v) noexcept { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } + ushort4& operator-=(ushort4 v) noexcept { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } + ushort4& operator*=(ushort4 v) noexcept { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } + ushort4& operator/=(ushort4 v) noexcept { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } + ushort4& operator%=(ushort4 v) noexcept { x %= v.x; y %= v.y; z %= v.z; w %= v.w; return *this; } + ushort4& operator&=(ushort4 v) noexcept { x &= v.x; y &= v.y; z &= v.z; w &= v.w; return *this; } + ushort4& operator|=(ushort4 v) noexcept { x |= v.x; y |= v.y; z |= v.z; w |= v.w; return *this; } + ushort4& operator^=(ushort4 v) noexcept { x ^= v.x; y ^= v.y; z ^= v.z; w ^= v.w; return *this; } + ushort4& operator>>=(ushort4 v) noexcept { x >>= v.x; y >>= v.y; z >>= v.z; w >>= v.w; return *this; } + ushort4& operator<<=(ushort4 v) noexcept { x <<= v.x; y <<= v.y; z <<= v.z; w <<= v.w; return *this; } + ushort4& operator+=(uint16 n) noexcept { x += n; y += n; z += n; w += n; return *this; } + ushort4& operator-=(uint16 n) noexcept { x -= n; y -= n; z -= n; w -= n; return *this; } + ushort4& operator*=(uint16 n) noexcept { x *= n; y *= n; z *= n; w *= n; return *this; } + ushort4& operator/=(uint16 n) noexcept { x /= n; y /= n; z /= n; w /= n; return *this; } + ushort4& operator%=(uint16 n) noexcept { x %= n; y %= n; z %= n; w %= n; return *this; } + ushort4& operator&=(uint16 n) noexcept { x &= n; y &= n; z &= n; w &= n; return *this; } + ushort4& operator|=(uint16 n) noexcept { x |= n; y |= n; z |= n; w |= n; return *this; } + ushort4& operator^=(uint16 n) noexcept { x ^= n; y ^= n; z ^= n; w ^= n; return *this; } + ushort4& operator>>=(uint16 n) noexcept { x >>= n; y >>= n; z >>= n; w >>= n; return *this; } + ushort4& operator<<=(uint16 n) noexcept { x <<= n; y <<= n; z <<= n; w <<= n; return *this; } + ushort4& operator=(uint16 n) noexcept { x = n; y = n; z = n; w = n; return *this; } + constexpr bool operator==(ushort4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(ushort4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + constexpr ushort4 operator<(ushort4 v) const noexcept + { + return ushort4(x < v.x ? UINT16_MAX : 0, y < v.y ? UINT16_MAX : 0, + z < v.z ? UINT16_MAX : 0, w < v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator>(ushort4 v) const noexcept + { + return ushort4(x > v.x ? UINT16_MAX : 0, y > v.y ? UINT16_MAX : 0, + z > v.z ? UINT16_MAX : 0, w > v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator<=(ushort4 v) const noexcept + { + return ushort4(x <= v.x ? UINT16_MAX : 0, y <= v.y ? UINT16_MAX : 0, + z <= v.z ? UINT16_MAX : 0, w <= v.w ? UINT16_MAX : 0); + } + constexpr ushort4 operator>=(ushort4 v) const noexcept + { + return ushort4(x >= v.x ? UINT16_MAX : 0, y >= v.y ? UINT16_MAX : 0, + z >= v.z ? UINT16_MAX : 0, w >= v.w ? UINT16_MAX : 0); + } + constexpr bool operator==(uint16 n) const noexcept { return *this == ushort4(n); } + constexpr bool operator!=(uint16 n) const noexcept { return *this != ushort4(n); } + constexpr ushort4 operator<(uint16 n) const noexcept { return *this < ushort4(n); } + constexpr ushort4 operator>(uint16 n) const noexcept { return *this > ushort4(n); } + constexpr ushort4 operator<=(uint16 n) const noexcept { return *this <= ushort4(n); } + constexpr ushort4 operator>=(uint16 n) const noexcept { return *this >= ushort4(n); } + + static const ushort4 zero, one, max; +}; + +inline const ushort4 ushort4::zero = ushort4(0u); +inline const ushort4 ushort4::one = ushort4(1u); +inline const ushort4 ushort4::max = ushort4(UINT16_MAX); + +//********************************************************************************************************************** +static constexpr ushort2 operator+(uint16 n, ushort2 v) noexcept { return ushort2(n) + v; } +static constexpr ushort2 operator-(uint16 n, ushort2 v) noexcept { return ushort2(n) - v; } +static constexpr ushort2 operator*(uint16 n, ushort2 v) noexcept { return ushort2(n) * v; } +static constexpr ushort2 operator/(uint16 n, ushort2 v) noexcept { return ushort2(n) / v; } +static constexpr ushort2 operator%(uint16 n, ushort2 v) noexcept { return ushort2(n) % v; } +static constexpr ushort2 operator&(uint16 n, ushort2 v) noexcept { return ushort2(n) & v; } +static constexpr ushort2 operator|(uint16 n, ushort2 v) noexcept { return ushort2(n) | v; } +static constexpr ushort2 operator^(uint16 n, ushort2 v) noexcept { return ushort2(n) ^ v; } +static constexpr ushort2 operator>>(uint16 n, ushort2 v) noexcept { return ushort2(n) >> v; } +static constexpr ushort2 operator<<(uint16 n, ushort2 v) noexcept { return ushort2(n) << v; } +static constexpr bool operator==(uint16 n, ushort2 v) noexcept { return ushort2(n) == v; } +static constexpr bool operator!=(uint16 n, ushort2 v) noexcept { return ushort2(n) != v; } +static constexpr ushort2 operator<(uint16 n, ushort2 v) noexcept { return ushort2(n) < v; } +static constexpr ushort2 operator>(uint16 n, ushort2 v) noexcept { return ushort2(n) > v; } +static constexpr ushort2 operator<=(uint16 n, ushort2 v) noexcept { return ushort2(n) <= v; } +static constexpr ushort2 operator>=(uint16 n, ushort2 v) noexcept { return ushort2(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ushort2 v) { return to_string(v.x) + " " + to_string(v.y); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (2bits) + */ +static constexpr uint16 getTrues(ushort2 v) noexcept +{ + return (v.x >> 15u) | ((v.y >> 15u) << 1u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ushort2 v) noexcept { return (v.x & v.y) == UINT16_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ushort2 v) noexcept { return (v.x | v.y) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ushort2 v) noexcept { return v.x | v.y; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ushort2 v) noexcept { return (v.x & v.y) != UINT16_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort2 equal(ushort2 a, ushort2 b) noexcept +{ + return ushort2(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort2 notEqual(ushort2 a, ushort2 b) noexcept +{ + return ushort2(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param a first vector to binary compare + * @param b second vector to binary compare + */ +static bool isBinaryLess(ushort2 a, ushort2 b) noexcept { return *((const uint32*)&a) < *((const uint32*)&b); } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr ushort2 select(ushort2 c, ushort2 t, ushort2 f) noexcept +{ + return ushort2(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ushort2 min(ushort2 a, ushort2 b) noexcept +{ + return ushort2(std::min(a.x, b.x), std::min(a.y, b.y)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ushort2 max(ushort2 a, ushort2 b) noexcept +{ + return ushort2(std::max(a.x, b.x), std::max(a.y, b.y)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ushort2 min(ushort2 a, ushort2 b, ushort2 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ushort2 max(ushort2 a, ushort2 b, ushort2 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ushort2 clamp(ushort2 v, ushort2 min, ushort2 max) noexcept +{ + return ushort2(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y)); +} + +//********************************************************************************************************************** +static constexpr ushort3 operator+(uint16 n, ushort3 v) noexcept { return ushort3(n) + v; } +static constexpr ushort3 operator-(uint16 n, ushort3 v) noexcept { return ushort3(n) - v; } +static constexpr ushort3 operator*(uint16 n, ushort3 v) noexcept { return ushort3(n) * v; } +static constexpr ushort3 operator/(uint16 n, ushort3 v) noexcept { return ushort3(n) / v; } +static constexpr ushort3 operator%(uint16 n, ushort3 v) noexcept { return ushort3(n) % v; } +static constexpr ushort3 operator&(uint16 n, ushort3 v) noexcept { return ushort3(n) & v; } +static constexpr ushort3 operator|(uint16 n, ushort3 v) noexcept { return ushort3(n) | v; } +static constexpr ushort3 operator^(uint16 n, ushort3 v) noexcept { return ushort3(n) ^ v; } +static constexpr ushort3 operator>>(uint16 n, ushort3 v) noexcept { return ushort3(n) >> v; } +static constexpr ushort3 operator<<(uint16 n, ushort3 v) noexcept { return ushort3(n) << v; } +static constexpr bool operator==(uint16 n, ushort3 v) noexcept { return ushort3(n) == v; } +static constexpr bool operator!=(uint16 n, ushort3 v) noexcept { return ushort3(n) != v; } +static constexpr ushort3 operator<(uint16 n, ushort3 v) noexcept { return ushort3(n) < v; } +static constexpr ushort3 operator>(uint16 n, ushort3 v) noexcept { return ushort3(n) > v; } +static constexpr ushort3 operator<=(uint16 n, ushort3 v) noexcept { return ushort3(n) <= v; } +static constexpr ushort3 operator>=(uint16 n, ushort3 v) noexcept { return ushort3(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ushort3 v) { return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z); } + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (3bits) + */ +static constexpr uint16 getTrues(ushort3 v) noexcept +{ + return (v.x >> 15u) | ((v.y >> 15u) << 1u) | ((v.z >> 15u) << 2u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ushort3 v) noexcept { return (v.x & v.y & v.z) == UINT16_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ushort3 v) noexcept { return (v.x | v.y | v.z) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ushort3 v) noexcept { return v.x | v.y | v.z; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ushort3 v) noexcept { return (v.x & v.y & v.z) != UINT16_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort3 equal(ushort3 a, ushort3 b) noexcept +{ + return ushort3(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0, a.z == b.z ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort3 notEqual(ushort3 a, ushort3 b) noexcept +{ + return ushort3(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0, a.z != b.z ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const ushort3& a, const ushort3& b) noexcept { return memcmp(&a, &b, sizeof(ushort3)) < 0; } + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param c control vector (contains is true or false) + * @param t contains components for true condition + * @param f contains components for false condition + */ +static constexpr ushort3 select(ushort3 c, ushort3 t, ushort3 f) noexcept +{ + return ushort3(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y, c.z & 0x8000u ? t.z : f.z); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ushort3 min(ushort3 a, ushort3 b) noexcept +{ + return ushort3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ushort3 max(ushort3 a, ushort3 b) noexcept +{ + return ushort3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ushort3 min(ushort3 a, ushort3 b, ushort3 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ushort3 max(ushort3 a, ushort3 b, ushort3 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ushort3 clamp(ushort3 v, ushort3 min, ushort3 max) noexcept +{ + return ushort3(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), std::clamp(v.z, min.z, max.z)); +} + +//********************************************************************************************************************** +static constexpr ushort4 operator+(uint16 n, const ushort4& v) noexcept { return ushort4(n) + v; } +static constexpr ushort4 operator-(uint16 n, const ushort4& v) noexcept { return ushort4(n) - v; } +static constexpr ushort4 operator*(uint16 n, const ushort4& v) noexcept { return ushort4(n) * v; } +static constexpr ushort4 operator/(uint16 n, const ushort4& v) noexcept { return ushort4(n) / v; } +static constexpr ushort4 operator%(uint16 n, const ushort4& v) noexcept { return ushort4(n) % v; } +static constexpr ushort4 operator&(uint16 n, const ushort4& v) noexcept { return ushort4(n) & v; } +static constexpr ushort4 operator|(uint16 n, const ushort4& v) noexcept { return ushort4(n) | v; } +static constexpr ushort4 operator^(uint16 n, const ushort4& v) noexcept { return ushort4(n) ^ v; } +static constexpr ushort4 operator>>(uint16 n, const ushort4& v) noexcept { return ushort4(n) >> v; } +static constexpr ushort4 operator<<(uint16 n, const ushort4& v) noexcept { return ushort4(n) << v; } +static constexpr bool operator==(uint16 n, const ushort4& v) noexcept { return ushort4(n) == v; } +static constexpr bool operator!=(uint16 n, const ushort4& v) noexcept { return ushort4(n) != v; } +static constexpr ushort4 operator<(uint16 n, const ushort4& v) noexcept { return ushort4(n) < v; } +static constexpr ushort4 operator>(uint16 n, const ushort4& v) noexcept { return ushort4(n) > v; } +static constexpr ushort4 operator<=(uint16 n, const ushort4& v) noexcept { return ushort4(n) <= v; } +static constexpr ushort4 operator>=(uint16 n, const ushort4& v) noexcept { return ushort4(n) >= v; } + +/** + * @brief Converts vector to the string. (space separated) + * @param v target vector to convert + */ +static string toString(ushort4 v) +{ + return to_string(v.x) + " " + to_string(v.y) + " " + to_string(v.z) + " " + to_string(v.w); +} + +/*********************************************************************************************************************** + * @brief Returns mask of vector components set to true. (4bits) + */ +static constexpr uint16 getTrues(ushort4 v) noexcept +{ + return (v.x >> 15u) | ((v.y >> 15u) << 1u) | ((v.z >> 15u) << 2u) | ((v.w >> 15u) << 3u); +} +/** + * @brief Returns true if all vector component bits are set true. + */ +static constexpr bool areAllTrue(ushort4 v) noexcept { return (v.x & v.y & v.z & v.w) == UINT16_MAX; } +/** + * @brief Returns false if all vector component bits are set false. + */ +static constexpr bool areAllFalse(ushort4 v) noexcept { return (v.x | v.y | v.z | v.w) == 0; } +/** + * @brief Returns true if any of vector component bits is set true. + */ +static constexpr bool areAnyTrue(ushort4 v) noexcept { return v.x | v.y | v.z | v.w; } +/** + * @brief Returns false if any of vector component bits is set false. + */ +static constexpr bool areAnyFalse(ushort4 v) noexcept { return (v.x & v.y & v.z & v.w) != UINT16_MAX; } + +/** + * @brief Compares two vectors component wise if they are equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort4 equal(ushort4 a, ushort4 b) noexcept +{ + return ushort4(a.x == b.x ? UINT16_MAX : 0, a.y == b.y ? UINT16_MAX : 0, + a.z == b.z ? UINT16_MAX : 0, a.w == b.w ? UINT16_MAX : 0); +} +/** + * @brief Compares two vectors component wise if they are not equal. + * + * @param a first vector to compare + * @param b second vector to compare + */ +static ushort4 notEqual(ushort4 a, ushort4 b) noexcept +{ + return ushort4(a.x != b.x ? UINT16_MAX : 0, a.y != b.y ? UINT16_MAX : 0, + a.z != b.z ? UINT16_MAX : 0, a.w != b.w ? UINT16_MAX : 0); +} + +/** + * @brief Returns true if first vector binary representation is less than the second. + * + * @param[in] a first vector to binary compare + * @param[in] b second vector to binary compare + */ +static bool isBinaryLess(const ushort4& a, const ushort4& b) noexcept +{ + return *((const uint64*)&a) < *((const uint64*)&b); +} + +/** + * @brief Selects between two vector components based on the control vector values. + * + * @param[in] c control vector (contains is true or false) + * @param[in] t contains components for true condition + * @param[in] f contains components for false condition + */ +static constexpr ushort4 select(ushort4 c, ushort4 t, ushort4 f) noexcept +{ + return ushort4(c.x & 0x8000u ? t.x : f.x, c.y & 0x8000u ? t.y : f.y, + c.z & 0x8000u ? t.z : f.z, c.w & 0x8000u ? t.w : f.w); +} + +/*********************************************************************************************************************** + * @brief Returns minimum value for each component of two vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + */ +static constexpr ushort4 min(ushort4 a, ushort4 b) noexcept +{ + return ushort4(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z), std::min(a.w, b.w)); +} +/** + * @brief Returns maximum value for each component of two vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + */ +static constexpr ushort4 max(ushort4 a, ushort4 b) noexcept +{ + return ushort4(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z), std::max(a.w, b.w)); +} +/** + * @brief Returns minimum value for each component of three vectors. + * + * @param a first vector to find minimum + * @param b second vector to find minimum + * @param c third vector to find minimum + */ +static constexpr ushort4 min(ushort4 a, ushort4 b, ushort4 c) noexcept { return min(min(a, b), c); } +/** + * @brief Returns maximum value for each component of three vectors. + * + * @param a first vector to find maximum + * @param b second vector to find maximum + * @param c third vector to find maximum + */ +static constexpr ushort4 max(ushort4 a, ushort4 b, ushort4 c) noexcept { return max(max(a, b), c); } + +/** + * @brief Clamps vector components between min and max values. + * + * @param v target vector to clamp + * @param min vector with minimum values + * @param max vector with maximum values + */ +static constexpr ushort4 clamp(ushort4 v, ushort4 min, ushort4 max) noexcept +{ + return ushort4(std::clamp(v.x, min.x, max.x), std::clamp(v.y, min.y, max.y), + std::clamp(v.z, min.z, max.z), std::clamp(v.w, min.w, max.w)); +} + +} // namespace math \ No newline at end of file diff --git a/tests/test-matrix.cpp b/tests/test-matrix.cpp index 4dbae08..aabb351 100644 --- a/tests/test-matrix.cpp +++ b/tests/test-matrix.cpp @@ -45,7 +45,7 @@ static void cmp(f32x4 a, float3 b, float tolerance = 1.0e-9f) if (difference > tolerance) throw runtime_error("Float3 vectors test failed."); } -static void cmp(f32x4x4 a, float4x4 b, float tolerance = 1.0e-9f) +static void cmp(const f32x4x4& a, float4x4 b, float tolerance = 1.0e-9f) { for (int c = 0; c < 4; c++) { @@ -62,7 +62,7 @@ static void cmp(f32x4x4 a, float4x4 b, float tolerance = 1.0e-9f) throw runtime_error("Float4 matrices test failed."); } } -static void cmp(f32x4x4 a, float3x3 b, float tolerance = 1.0e-9f) +static void cmp(const f32x4x4& a, float3x3 b, float tolerance = 1.0e-9f) { for (int c = 0; c < 3; c++) { diff --git a/tests/test-vector.cpp b/tests/test-vector.cpp index 342685e..2a88e2d 100644 --- a/tests/test-vector.cpp +++ b/tests/test-vector.cpp @@ -165,8 +165,8 @@ static void testFloatVectors() cmp(simdSin, sin(vecRight)); cmp(simdCos, cos(vecRight)); } - cmp((f32x4)(f16x4)simdLeft, vecLeft, 1.0e-3f); - cmp((f32x4)(f16x4)simdRight, vecRight, 1.0e-3f); + cmp((f32x4)simdLeft, vecLeft, 1.0e-3f); + cmp((f32x4)simdRight, vecRight, 1.0e-3f); } //********************************************************************************************************************** From 504daddb173738ab8e76fed47b2ef31a97c8ca7f Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Sun, 19 Jul 2026 15:08:40 +0300 Subject: [PATCH 02/14] Fixes and improvements --- include/math/common.hpp | 103 ++++++++++---- include/math/simd/vector/float.hpp | 87 +++++++++--- include/math/simd/vector/half.hpp | 102 +++++++++++-- include/math/simd/vector/int.hpp | 54 +++++-- include/math/simd/vector/uint.hpp | 52 ++++++- include/math/types.hpp | 7 +- include/math/vector/double.hpp | 221 +++++++++-------------------- include/math/vector/float.hpp | 191 +++++++------------------ include/math/vector/half.hpp | 185 ++++++++---------------- include/math/vector/int.hpp | 64 +-------- include/math/vector/long.hpp | 88 +----------- include/math/vector/sbyte.hpp | 15 +- include/math/vector/short.hpp | 40 +----- include/math/vector/uint.hpp | 42 +++++- include/math/vector/ulong.hpp | 60 +++++++- include/math/vector/ushort.hpp | 33 +++-- 16 files changed, 635 insertions(+), 709 deletions(-) diff --git a/include/math/common.hpp b/include/math/common.hpp index fc28ed0..71260a8 100644 --- a/include/math/common.hpp +++ b/include/math/common.hpp @@ -18,7 +18,6 @@ */ #pragma once -#include "math/types.hpp" #include #include #include @@ -29,52 +28,51 @@ namespace math using namespace std; /** - * @brief Returns the minimum of three floating point values. + * @brief Returns the minimum of three values. * + * @tparam T target value type * @param a first value to find minimum * @param b second value to find minimum * @param c third value to find minimum */ -static constexpr float min(float a, float b, float c) { return std::min(std::min(a, b), c); } +template +static constexpr const T& min(const T& a, const T& b, const T& c) { return std::min(std::min(a, b), c); } /** - * @brief Returns the maximum of three floating point values. + * @brief Returns the maximum of three values. * + * @tparam T target value type * @param a first value to find maximum * @param b second value to find maximum * @param c third value to find maximum */ -static constexpr float max(float a, float b, float c) { return std::max(std::max(a, b), c); } +template +static constexpr const T& max(const T& a, const T& b, const T& c) { return std::max(std::max(a, b), c); } + /** - * @brief Returns the minimum of signed integer values. - * - * @param a first value to find minimum - * @param b second value to find minimum - * @param c third value to find minimum + * @brief Clamps float value between the 0.0 and 1.0. (Inclusive range) + * @param v target floating-point value to saturate */ -static constexpr int32 min(int32 a, int32 b, int32 c) { return std::min(std::min(a, b), c); } +static constexpr float saturate(float v) { return std::clamp(v, 0.0f, 1.0f); } /** - * @brief Returns the maximum of signed integer values. - * - * @param a first value to find maximum - * @param b second value to find maximum - * @param c third value to find maximum + * @brief Clamps float value between the 0.0 and 1.0. (Inclusive range) + * @param v target floating-point value to saturate */ -static constexpr int32 max(int32 a, int32 b, int32 c) { return std::max(std::max(a, b), c); } +static constexpr double saturate(double v) { return std::clamp(v, 0.0, 1.0); } /** - * @brief Clamps float value between the 0.0f and 1.0f. (Inclusive range) - * @param v target float value to saturate + * @brief Returns specified float value sign. + * @param v target floating-point value */ -static constexpr float saturate(float v) { return std::clamp(v, 0.0f, 1.0f); } - +static float sign(float v) noexcept { return std::signbit(v) ? -1.0f : 1.0f; } /** - * @brief Returns specified floating point value sign. - * @param v target value + * @brief Returns specified float value sign. + * @param v target floating-point value */ -static float sign(float v) noexcept { return std::signbit(v) ? -1.0f : 1.0f; } +static double sign(double v) noexcept { return std::signbit(v) ? -1.0 : 1.0; } + /** * @brief Remaps specified value to the 0.0 - 1.0 range. - * @param v target value to repeat + * @param v target floating-point value to repeat */ static float repeat(float v) noexcept { @@ -84,6 +82,18 @@ static float repeat(float v) noexcept return std::fmod(v, 1.0f); return v; } +/** + * @brief Remaps specified value to the 0.0 - 1.0 range. + * @param v target floating-point value to repeat + */ +static double repeat(double v) noexcept +{ + if (v < 0.0) + return 1.0 - std::fmod(-v, 1.0); + if (v >= 1.0) + return std::fmod(v, 1.0); + return v; +} /** * @brief Linearly interpolates between a and b values using t. @@ -92,7 +102,16 @@ static float repeat(float v) noexcept * @param b maximum value (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static float lerp(float a, float b, float t) noexcept { return a + t * (b - a); } +static constexpr float lerp(float a, float b, float t) noexcept { return a + t * (b - a); } +/** + * @brief Linearly interpolates between a and b values using t. + * + * @param a minimum value (t == 0.0) + * @param b maximum value (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + */ +static constexpr double lerp(double a, double b, double t) noexcept { return a + t * (b - a); } + /** * @brief Linearly interpolates between a and b values using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -106,6 +125,20 @@ static float lerpDelta(float a, float b, float f, float dt) noexcept { return a + (1.0f - std::pow(f, dt)) * (b - a); } +/** + * @brief Linearly interpolates between a and b values using t, taking into account delta time. + * @note Always use this function instead of basic lerp() when you have variable delta time! + * + * @param a minimum value (t == 0.0) + * @param b maximum value (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + * @param dt current delta time + */ +static double lerpDelta(double a, double b, double f, double dt) noexcept +{ + return a + (1.0 - std::pow(f, dt)) * (b - a); +} + /** * @brief Applies gain function to the x value. * @note The function is symmetric when x == 0.5. @@ -118,14 +151,24 @@ static float gain(float x, float k) noexcept auto a = 0.5f * std::pow(2.0f * ((x < 0.5f) ? x : 1.0f - x), k); return (x < 0.5f) ? a : 1.0f - a; } - -// TODO: double variants +/** + * @brief Applies gain function to the x value. + * @note The function is symmetric when x == 0.5. + * + * @param x target value to gain (0.0 - 1.0) + * @param k gain factor + */ +static double gain(double x, double k) noexcept +{ + auto a = 0.5 * std::pow(2.0 * ((x < 0.5) ? x : 1.0 - x), k); + return (x < 0.5) ? a : 1.0 - a; +} /** * @brief Returns true if specified value is a power of 2. * - * @tparam T type of the value - * @param v target value to check + * @tparam T integer type of the value + * @param v target integer value to check */ template static constexpr bool isPowerOf2(T v) noexcept diff --git a/include/math/simd/vector/float.hpp b/include/math/simd/vector/float.hpp index eaf9542..b2e460f 100644 --- a/include/math/simd/vector/float.hpp +++ b/include/math/simd/vector/float.hpp @@ -139,6 +139,16 @@ struct [[nodiscard]] f32x4 f32x4(_simd_f128 data) noexcept : data(data) { } #endif + explicit f32x4(f16x4 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + data = _mm_cvtph_ps(v.data); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = vcvt_f32_f16(v.data); + #else + floats = (float4)v.halfs; + #endif + } explicit f32x4(u32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -159,17 +169,6 @@ struct [[nodiscard]] f32x4 floats = v.floats; #endif } - explicit f32x4(f16x4 v) noexcept - { - #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtph_ps(v.data); - #elif defined(MATH_SIMD_SUPPORT_NEON) - data = vcvt_f32_f16(v.data); - #else - floats = (float4)v.halfs; - #endif - } - /******************************************************************************************************************* * @brief Creates a new 4-component SIMD vector of 32-bit floating-point values. (float4) @@ -214,6 +213,25 @@ struct [[nodiscard]] f32x4 floats = *v; #endif } + + explicit f32x4(half4 v) noexcept { *this = (f32x4)f16x4(v); } + explicit f32x4(long4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(ulong4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(int4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(uint4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(short4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(ushort4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(sbyte4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(byte4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(half3 v) noexcept { *this = (f32x4)f16x4(v); } + explicit f32x4(long3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(ulong3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(int3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(uint3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(short3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(ushort3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(sbyte3 v) noexcept { *this = (f32x4)float3(v); } + explicit f32x4(byte3 v) noexcept { *this = (f32x4)float3(v); } /******************************************************************************************************************* * @brief Loads 4-component SIMD vector of 32-bit floating-point values. @@ -391,6 +409,16 @@ struct [[nodiscard]] f32x4 */ float operator[](psize i) const noexcept { return floats[i]; } + explicit operator f16x4() const noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + return vcvt_f16_f32(v.data); + #else + return f16x4((half4)floats); + #endif + } explicit operator u32x4() const noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -411,20 +439,37 @@ struct [[nodiscard]] f32x4 return i32x4((uint4)floats); #endif } - explicit operator f16x4() const noexcept - { - #if defined(MATH_SIMD_SUPPORT_AVX2) - return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT); - #elif defined(MATH_SIMD_SUPPORT_NEON) - return vcvt_f16_f32(v.data); - #else - return f16x4((half4)floats); - #endif - } explicit operator float4() const noexcept { return floats; } + explicit operator half4() const noexcept { return (half4)floats; } + explicit operator long4() const noexcept { return (long4)floats; } + explicit operator ulong4() const noexcept { return (ulong4)floats; } + explicit operator int4() const noexcept { return (int4)floats; } + explicit operator uint4() const noexcept { return (uint4)floats; } + explicit operator short4() const noexcept { return (short4)floats; } + explicit operator ushort4() const noexcept { return (ushort4)floats; } + explicit operator sbyte4() const noexcept { return (sbyte4)floats; } + explicit operator byte4() const noexcept { return (byte4)floats; } explicit operator float3() const noexcept { return (float3)floats; } + explicit operator half3() const noexcept { return (half3)floats; } + explicit operator long3() const noexcept { return (long3)floats; } + explicit operator ulong3() const noexcept { return (ulong3)floats; } + explicit operator int3() const noexcept { return (int3)floats; } + explicit operator uint3() const noexcept { return (uint3)floats; } + explicit operator short3() const noexcept { return (short3)floats; } + explicit operator ushort3() const noexcept { return (ushort3)floats; } + explicit operator sbyte3() const noexcept { return (sbyte3)floats; } + explicit operator byte3() const noexcept { return (byte3)floats; } explicit operator float2() const noexcept { return (float2)floats; } + explicit operator half2() const noexcept { return (half2)floats; } + explicit operator long2() const noexcept { return (long2)floats; } + explicit operator ulong2() const noexcept { return (ulong2)floats; } + explicit operator int2() const noexcept { return (int2)floats; } + explicit operator uint2() const noexcept { return (uint2)floats; } + explicit operator short2() const noexcept { return (short2)floats; } + explicit operator ushort2() const noexcept { return (ushort2)floats; } + explicit operator sbyte2() const noexcept { return (sbyte2)floats; } + explicit operator byte2() const noexcept { return (byte2)floats; } //****************************************************************************************************************** f32x4 operator+(f32x4 v) const noexcept diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index 1589b0c..6c012ce 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -50,7 +50,7 @@ struct [[nodiscard]] f16x4 #if defined(MATH_SIMD_SUPPORT_AVX2) data = _mm_setzero_si128(); #elif defined(MATH_SIMD_SUPPORT_NEON) - data = vdup_n_f16(0.0f); + data = vdup_n_f16(0.0_hf); #else halfs = half4::zero; #endif @@ -128,6 +128,55 @@ struct [[nodiscard]] f16x4 f16x4(_simd_f64 data) noexcept : data(data) { } #endif + /******************************************************************************************************************* + * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) + * @param v target 4 component vector value + */ + explicit f16x4(half4 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + data = _mm_cvtps_ph(_mm_set_ps(v.w, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = (float16x4_t){ v.x, v.y, v.z, v.w }; + #else + halfs = v; + #endif + } + /** + * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) + * @warning This constructor duplicates Z component to the W component! + * @param v target 3 component vector value + */ + explicit f16x4(half3 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_AVX2) + data = _mm_cvtps_ph(_mm_set_ps(v.z, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = (float16x4_t){ v.x, v.y, v.z, v.z }; + #else + halfs = half4(v, v.z); + #endif + } + + explicit f16x4(float4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(long4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(ulong4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(int4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(uint4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(short4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(ushort4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(sbyte4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(byte4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(float3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(long3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(ulong3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(int3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(uint3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(short3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(ushort3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(sbyte3 v) noexcept { *this = (f16x4)half3(v); } + explicit f16x4(byte3 v) noexcept { *this = (f16x4)half3(v); } + /******************************************************************************************************************* * @brief Returns SIMD vector first component value. */ @@ -183,9 +232,36 @@ struct [[nodiscard]] f16x4 */ half operator[](psize i) const noexcept { return halfs[i]; } + explicit operator float4() const noexcept { return (float4)halfs; } explicit operator half4() const noexcept { return halfs; } + explicit operator long4() const noexcept { return (long4)halfs; } + explicit operator ulong4() const noexcept { return (ulong4)halfs; } + explicit operator int4() const noexcept { return (int4)halfs; } + explicit operator uint4() const noexcept { return (uint4)halfs; } + explicit operator short4() const noexcept { return (short4)halfs; } + explicit operator ushort4() const noexcept { return (ushort4)halfs; } + explicit operator sbyte4() const noexcept { return (sbyte4)halfs; } + explicit operator byte4() const noexcept { return (byte4)halfs; } + explicit operator float3() const noexcept { return (float3)halfs; } explicit operator half3() const noexcept { return (half3)halfs; } + explicit operator long3() const noexcept { return (long3)halfs; } + explicit operator ulong3() const noexcept { return (ulong3)halfs; } + explicit operator int3() const noexcept { return (int3)halfs; } + explicit operator uint3() const noexcept { return (uint3)halfs; } + explicit operator short3() const noexcept { return (short3)halfs; } + explicit operator ushort3() const noexcept { return (ushort3)halfs; } + explicit operator sbyte3() const noexcept { return (sbyte3)halfs; } + explicit operator byte3() const noexcept { return (byte3)halfs; } + explicit operator float2() const noexcept { return (float2)halfs; } explicit operator half2() const noexcept { return (half2)halfs; } + explicit operator long2() const noexcept { return (long2)halfs; } + explicit operator ulong2() const noexcept { return (ulong2)halfs; } + explicit operator int2() const noexcept { return (int2)halfs; } + explicit operator uint2() const noexcept { return (uint2)halfs; } + explicit operator short2() const noexcept { return (short2)halfs; } + explicit operator ushort2() const noexcept { return (ushort2)halfs; } + explicit operator sbyte2() const noexcept { return (sbyte2)halfs; } + explicit operator byte2() const noexcept { return (byte2)halfs; } // TODO: math functions after adding AVX512 support. @@ -194,23 +270,23 @@ struct [[nodiscard]] f16x4 }; //********************************************************************************************************************** -inline const f16x4 f16x4::zero = f16x4(0.0f); -inline const f16x4 f16x4::one = f16x4(1.0f); -inline const f16x4 f16x4::minusOne = f16x4(-1.0f); +inline const f16x4 f16x4::zero = f16x4(0.0_hf); +inline const f16x4 f16x4::one = f16x4(1.0_hf); +inline const f16x4 f16x4::minusOne = f16x4(-1.0_hf); inline const f16x4 f16x4::min = f16x4(FLT16_MIN); inline const f16x4 f16x4::minusMin = f16x4(-FLT16_MIN); inline const f16x4 f16x4::max = f16x4(FLT16_MAX); inline const f16x4 f16x4::minusMax = f16x4(-FLT16_MAX); inline const f16x4 f16x4::epsilon = f16x4(FLT16_EPSILON); -inline const f16x4 f16x4::inf = f16x4(INFINITY); -inline const f16x4 f16x4::minusInf = f16x4(-INFINITY); -inline const f16x4 f16x4::nan = f16x4(NAN); -inline const f16x4 f16x4::left = f16x4(-1.0f, 0.0f, 0.0f, 0.0f); -inline const f16x4 f16x4::right = f16x4(1.0f, 0.0f, 0.0f, 0.0f); -inline const f16x4 f16x4::bottom = f16x4(0.0f, -1.0f, 0.0f, 0.0f); -inline const f16x4 f16x4::top = f16x4(0.0f, 1.0f, 0.0f, 0.0f); -inline const f16x4 f16x4::back = f16x4(0.0f, 0.0f, -1.0f, 0.0f); -inline const f16x4 f16x4::front = f16x4(0.0f, 0.0f, 1.0f, 0.0f); +inline const f16x4 f16x4::inf = f16x4((half)INFINITY); +inline const f16x4 f16x4::minusInf = f16x4((half)-INFINITY); +inline const f16x4 f16x4::nan = f16x4((half)NAN); +inline const f16x4 f16x4::left = f16x4(-1.0_hf, 0.0_hf, 0.0_hf, 0.0_hf); +inline const f16x4 f16x4::right = f16x4(1.0_hf, 0.0_hf, 0.0_hf, 0.0_hf); +inline const f16x4 f16x4::bottom = f16x4(0.0_hf, -1.0_hf, 0.0_hf, 0.0_hf); +inline const f16x4 f16x4::top = f16x4(0.0_hf, 1.0_hf, 0.0_hf, 0.0_hf); +inline const f16x4 f16x4::back = f16x4(0.0_hf, 0.0_hf, -1.0_hf, 0.0_hf); +inline const f16x4 f16x4::front = f16x4(0.0_hf, 0.0_hf, 1.0_hf, 0.0_hf); } // namespace math #endif \ No newline at end of file diff --git a/include/math/simd/vector/int.hpp b/include/math/simd/vector/int.hpp index 5c3081d..ac448ec 100644 --- a/include/math/simd/vector/int.hpp +++ b/include/math/simd/vector/int.hpp @@ -123,17 +123,9 @@ struct [[nodiscard]] i32x4 } #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) - /** - * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) - * @param data target vector SIMD data - */ i32x4(_simd_i128 data) noexcept : data(data) { } #endif - /** - * @brief Creates a new 4-component SIMD vector of 32-bit signed integer values. (int4) - * @param v target vector unsigned integer SIMD data - */ explicit i32x4(u32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_SSE) @@ -188,6 +180,25 @@ struct [[nodiscard]] i32x4 ints = *v; #endif } + + explicit i32x4(float4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(half4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(long4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(ulong4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(uint4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(short4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(ushort4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(sbyte4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(byte4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(float3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(half3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(long3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(ulong3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(uint3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(short3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(ushort3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(sbyte3 v) noexcept { *this = (i32x4)int3(v); } + explicit i32x4(byte3 v) noexcept { *this = (i32x4)int3(v); } /******************************************************************************************************************* * @brief Loads 4-component SIMD vector of aligned 32-bit signed integer values. (int4) @@ -361,9 +372,36 @@ struct [[nodiscard]] i32x4 #endif } + explicit operator float4() const noexcept { return (float4)ints; } + explicit operator half4() const noexcept { return (half4)ints; } + explicit operator long4() const noexcept { return (long4)ints; } + explicit operator ulong4() const noexcept { return (ulong4)ints; } explicit operator int4() const noexcept { return ints; } + explicit operator uint4() const noexcept { return (uint4)ints; } + explicit operator short4() const noexcept { return (short4)ints; } + explicit operator ushort4() const noexcept { return (ushort4)ints; } + explicit operator sbyte4() const noexcept { return (sbyte4)ints; } + explicit operator byte4() const noexcept { return (byte4)ints; } + explicit operator float3() const noexcept { return (float3)ints; } + explicit operator half3() const noexcept { return (half3)ints; } + explicit operator long3() const noexcept { return (long3)ints; } + explicit operator ulong3() const noexcept { return (ulong3)ints; } explicit operator int3() const noexcept { return (int3)ints; } + explicit operator uint3() const noexcept { return (uint3)ints; } + explicit operator short3() const noexcept { return (short3)ints; } + explicit operator ushort3() const noexcept { return (ushort3)ints; } + explicit operator sbyte3() const noexcept { return (sbyte3)ints; } + explicit operator byte3() const noexcept { return (byte3)ints; } + explicit operator float2() const noexcept { return (float2)ints; } + explicit operator half2() const noexcept { return (half2)ints; } + explicit operator long2() const noexcept { return (long2)ints; } + explicit operator ulong2() const noexcept { return (ulong2)ints; } explicit operator int2() const noexcept { return (int2)ints; } + explicit operator uint2() const noexcept { return (uint2)ints; } + explicit operator short2() const noexcept { return (short2)ints; } + explicit operator ushort2() const noexcept { return (ushort2)ints; } + explicit operator sbyte2() const noexcept { return (sbyte2)ints; } + explicit operator byte2() const noexcept { return (byte2)ints; } //****************************************************************************************************************** i32x4 operator+(i32x4 v) const noexcept diff --git a/include/math/simd/vector/uint.hpp b/include/math/simd/vector/uint.hpp index 64f8702..265968a 100644 --- a/include/math/simd/vector/uint.hpp +++ b/include/math/simd/vector/uint.hpp @@ -19,7 +19,7 @@ #pragma once #include "math/simd/types.hpp" -#include "math/vector/float.hpp" +#include "math/vector/double.hpp" namespace math { @@ -130,10 +130,6 @@ struct [[nodiscard]] u32x4 } #if defined(MATH_SIMD_SUPPORT_SSE) || defined(MATH_SIMD_SUPPORT_NEON) - /** - * @brief Creates a new 4-component SIMD vector of 32-bit unsigned integer values. (uint4) - * @param data target vector SIMD data - */ u32x4(_simd_u128 data) noexcept : data(data) { } #endif @@ -180,6 +176,25 @@ struct [[nodiscard]] u32x4 uints = *v; #endif } + + explicit u32x4(float4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(half4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(long4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(ulong4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(int4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(short4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(ushort4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(sbyte4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(byte4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(float3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(half3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(long3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(ulong3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(int3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(short3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(ushort3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(sbyte3 v) noexcept { *this = (u32x4)uint3(v); } + explicit u32x4(byte3 v) noexcept { *this = (u32x4)uint3(v); } /******************************************************************************************************************* * @brief Loads 4-component SIMD vector of aligned 32-bit unsigned integer values. (uint4) @@ -342,9 +357,36 @@ struct [[nodiscard]] u32x4 */ uint32 operator[](psize i) const noexcept { return uints[i]; } + explicit operator float4() const noexcept { return (float4)uints; } + explicit operator half4() const noexcept { return (half4)uints; } + explicit operator long4() const noexcept { return (long4)uints; } + explicit operator ulong4() const noexcept { return (ulong4)uints; } + explicit operator int4() const noexcept { return (int4)uints; } explicit operator uint4() const noexcept { return uints; } + explicit operator short4() const noexcept { return (short4)uints; } + explicit operator ushort4() const noexcept { return (ushort4)uints; } + explicit operator sbyte4() const noexcept { return (sbyte4)uints; } + explicit operator byte4() const noexcept { return (byte4)uints; } + explicit operator float3() const noexcept { return (float3)uints; } + explicit operator half3() const noexcept { return (half3)uints; } + explicit operator long3() const noexcept { return (long3)uints; } + explicit operator ulong3() const noexcept { return (ulong3)uints; } + explicit operator int3() const noexcept { return (int3)uints; } explicit operator uint3() const noexcept { return (uint3)uints; } + explicit operator short3() const noexcept { return (short3)uints; } + explicit operator ushort3() const noexcept { return (ushort3)uints; } + explicit operator sbyte3() const noexcept { return (sbyte3)uints; } + explicit operator byte3() const noexcept { return (byte3)uints; } + explicit operator float2() const noexcept { return (float2)uints; } + explicit operator half2() const noexcept { return (half2)uints; } + explicit operator long2() const noexcept { return (long2)uints; } + explicit operator ulong2() const noexcept { return (ulong2)uints; } + explicit operator int2() const noexcept { return (int2)uints; } explicit operator uint2() const noexcept { return (uint2)uints; } + explicit operator short2() const noexcept { return (short2)uints; } + explicit operator ushort2() const noexcept { return (ushort2)uints; } + explicit operator sbyte2() const noexcept { return (sbyte2)uints; } + explicit operator byte2() const noexcept { return (byte2)uints; } //****************************************************************************************************************** u32x4 operator+(u32x4 v) const noexcept diff --git a/include/math/types.hpp b/include/math/types.hpp index a54a17d..f0c2881 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -74,8 +74,13 @@ typedef uint64_t uint64; typedef size_t psize; /** - * @brief An IEEE-754 half-precision 16-bit floating point number. + * @brief An IEEE-754 half-precision 16-bit floating-point number. */ typedef _Float16 half; +/** + * @brief Half-precision 16-bit floating-point number literal. + */ +constexpr half operator""_hf(long double val) { return static_cast(val); } + } // namespace math \ No newline at end of file diff --git a/include/math/vector/double.hpp b/include/math/vector/double.hpp index 5a220d5..cc2a97d 100644 --- a/include/math/vector/double.hpp +++ b/include/math/vector/double.hpp @@ -19,8 +19,7 @@ */ #pragma once -#include "math/common.hpp" -#include "math/vector/half.hpp" +#include "math/vector/float.hpp" namespace math { @@ -46,50 +45,16 @@ struct [[nodiscard]] double2 * @param y second vector component value */ constexpr double2(double x, double y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr double2(half2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr double2(long2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr double2(ulong2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr double2(int2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr double2(uint2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ + + constexpr double2(float2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(half2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(long2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(ulong2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(int2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(uint2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(short2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ constexpr double2(ushort2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ constexpr double2(sbyte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit floating-point values. - * @param xy first and second vector component value - */ constexpr double2(byte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } /******************************************************************************************************************* @@ -111,6 +76,7 @@ struct [[nodiscard]] double2 return ((double*)this)[i]; } + constexpr explicit operator float2() const noexcept { return float2((float)x, (float)y); } constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } @@ -120,6 +86,9 @@ struct [[nodiscard]] double2 constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + + // TODO: 2/3 overrides, also add missing doubleX conversions in other files. + // Also looks like we will need to add 2/3 overrides also for all integer vector types. //****************************************************************************************************************** constexpr double2 operator+(double2 v) const noexcept { return double2(x + v.x, y + v.y); } @@ -176,7 +145,7 @@ inline constexpr double2 double2::min = double2(DBL_MIN); inline constexpr double2 double2::minusMin = double2(-DBL_MIN); inline constexpr double2 double2::max = double2(DBL_MAX); inline constexpr double2 double2::minusMax = double2(-DBL_MAX); -inline constexpr double2 double2::epsilon = double2(FLT_EPSILON); +inline constexpr double2 double2::epsilon = double2(DBL_EPSILON); inline constexpr double2 double2::inf = double2(INFINITY); inline constexpr double2 double2::minusInf = double2(-INFINITY); inline constexpr double2 double2::nan = double2(NAN); @@ -222,50 +191,26 @@ struct [[nodiscard]] double3 * @param yz second and third vector component value */ constexpr double3(double x, double2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr double3(half3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr double3(long3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr double3(ulong3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr double3(int3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr double3(uint3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ + + constexpr double3(float4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(float3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(half4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(half3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(long4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(long3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(ulong4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(ulong3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(int4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(int3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(uint4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(uint3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } + constexpr double3(short4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } constexpr double3(short3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr double3(ushort4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } constexpr double3(ushort3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr double3(sbyte4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } constexpr double3(sbyte3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr double3(byte4 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } constexpr double3(byte3 xyz) noexcept : x((double)xyz.x), y((double)xyz.y), z((double)xyz.z) { } /******************************************************************************************************************* @@ -287,6 +232,7 @@ struct [[nodiscard]] double3 return ((double*)this)[i]; } + constexpr explicit operator float3() const noexcept { return float3((float)x, (float)y, (float)z); } constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } @@ -297,6 +243,7 @@ struct [[nodiscard]] double3 constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator double2() const noexcept { return double2(x, y); } + constexpr explicit operator float2() const noexcept { return float2((float)x, (float)y); } constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } @@ -362,7 +309,7 @@ inline constexpr double3 double3::min = double3(DBL_MIN); inline constexpr double3 double3::minusMin = double3(-DBL_MIN); inline constexpr double3 double3::max = double3(DBL_MAX); inline constexpr double3 double3::minusMax = double3(-DBL_MAX); -inline constexpr double3 double3::epsilon = double3(FLT_EPSILON); +inline constexpr double3 double3::epsilon = double3(DBL_EPSILON); inline constexpr double3 double3::inf = double3(INFINITY); inline constexpr double3 double3::minusInf = double3(-INFINITY); inline constexpr double3 double3::nan = double3(NAN); @@ -443,50 +390,16 @@ struct [[nodiscard]] double4 * @param yzw second, third and fourth vector component value */ constexpr double4(double x, double3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr double4(half4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr double4(long4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr double4(ulong4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr double4(int4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr double4(uint4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ + + constexpr double4(float4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + constexpr double4(half4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + constexpr double4(long4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + constexpr double4(ulong4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + constexpr double4(int4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } + constexpr double4(uint4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } constexpr double4(short4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr double4(ushort4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr double4(sbyte4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr double4(byte4 xyzw) noexcept : x((double)xyzw.x), y((double)xyzw.y), z((double)xyzw.z), w((double)xyzw.w) { } /******************************************************************************************************************* @@ -508,6 +421,7 @@ struct [[nodiscard]] double4 return ((double*)this)[i]; } + constexpr explicit operator float4() const noexcept { return float4((float)x, (float)y, (float)z, (float)w); } constexpr explicit operator half4() const noexcept { return half4((half)x, (half)y, (half)z, (half)w); } constexpr explicit operator long4() const noexcept { return long4((int64)x, (int64)y, (int64)z, (int64)w); } constexpr explicit operator ulong4() const noexcept { return ulong4((uint64)x, (uint64)y, (uint64)z, (uint64)w); } @@ -518,6 +432,7 @@ struct [[nodiscard]] double4 constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } constexpr explicit operator double3() const noexcept { return double3(x, y, z); } + constexpr explicit operator float3() const noexcept { return float3((float)x, (float)y, (float)z); } constexpr explicit operator half3() const noexcept { return half3((half)x, (half)y, (half)z); } constexpr explicit operator long3() const noexcept { return long3((int64)x, (int64)y, (int64)z); } constexpr explicit operator ulong3() const noexcept { return ulong3((uint64)x, (uint64)y, (uint64)z); } @@ -528,6 +443,7 @@ struct [[nodiscard]] double4 constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator double2() const noexcept { return double2(x, y); } + constexpr explicit operator float2() const noexcept { return float2((float)x, (float)y); } constexpr explicit operator half2() const noexcept { return half2((half)x, (half)y); } constexpr explicit operator long2() const noexcept { return long2((int64)x, (int64)y); } constexpr explicit operator ulong2() const noexcept { return ulong2((uint64)x, (uint64)y); } @@ -596,7 +512,7 @@ inline constexpr double4 double4::min = double4(DBL_MIN); inline constexpr double4 double4::minusMin = double4(-DBL_MIN); inline constexpr double4 double4::max = double4(DBL_MAX); inline constexpr double4 double4::minusMax = double4(-DBL_MAX); -inline constexpr double4 double4::epsilon = double4(FLT_EPSILON); +inline constexpr double4 double4::epsilon = double4(DBL_EPSILON); inline constexpr double4 double4::inf = double4(INFINITY); inline constexpr double4 double4::minusInf = double4(-INFINITY); inline constexpr double4 double4::nan = double4(NAN); @@ -625,7 +541,7 @@ static string toString(double2 v) { return to_string(v.x) + " " + to_string(v.y) * @param a first vector to compare * @param b second vector to compare */ -static uint2 equal(double2 a, double4 b) noexcept +static uint2 equal(double2 a, double2 b) noexcept { return uint2(a.x == b.x ? UINT32_MAX : 0, a.y == b.y ? UINT32_MAX : 0); } @@ -635,7 +551,7 @@ static uint2 equal(double2 a, double4 b) noexcept * @param a first vector to compare * @param b second vector to compare */ -static uint2 notEqual(double2 a, double4 b) noexcept +static uint2 notEqual(double2 a, double2 b) noexcept { return uint2(a.x != b.x ? UINT32_MAX : 0, a.y != b.y ? UINT32_MAX : 0); } @@ -646,7 +562,7 @@ static uint2 notEqual(double2 a, double4 b) noexcept * @param a first vector to binary compare * @param b second vector to binary compare */ -static bool isBinaryLess(double2 a, double2 b) noexcept { return *((const int64*)&a) < *((const int64*)&b); } +static bool isBinaryLess(double2 a, double2 b) noexcept { return memcmp(&a, &b, sizeof(double2)) < 0; } /** * @brief Selects between two vector components based on the control vector values. @@ -706,10 +622,7 @@ static constexpr double2 clamp(double2 v, double2 min, double2 max) noexcept * @brief Clamps vector components between the 0.0 and 1.0. (Inclusive range) * @param v target vector to saturate */ -static constexpr double2 saturate(double2 v) noexcept -{ - return double2(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0)); -} +static constexpr double2 saturate(double2 v) noexcept { return double2(saturate(v.x), saturate(v.y)); } /*********************************************************************************************************************** * @brief Fused multiply add, calculates: mul1 * mul2 + add @@ -816,7 +729,7 @@ static double distance(double2 a, double2 b) noexcept { return length(a - b); } * @param a first vector * @param b second vector */ -static constexpr bool isClose(double2 a, double2 b, double maxDistSq = 1.0e-12f) noexcept +static constexpr bool isClose(double2 a, double2 b, double maxDistSq = 1.0e-28) noexcept { return distanceSq(a, b) <= maxDistSq; } @@ -832,7 +745,7 @@ static double2 normalize(double2 v) noexcept { return v * (1.0 / length(v)); } * @param v target vector to check * @param tolerance floating point precision tolerance */ -static bool isNormalized(double2 v, double tolerance = 1.0e-6f) noexcept +static bool isNormalized(double2 v, double tolerance = 1.0e-14) noexcept { return std::abs(lengthSq(v) - 1.0) <= tolerance; } @@ -855,7 +768,7 @@ static double2 repeat(double2 v) noexcept { return double2(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static double2 lerp(double2 a, double2 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double2 lerp(double2 a, double2 b, double t) noexcept { return a * (1.0 - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -886,8 +799,8 @@ static double2 pow(double2 b, double2 e) noexcept { return double2(std::pow(b.x, */ static double2 gain(double2 x, double2 k) noexcept { - auto a = double2(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); - return select(x < 0.5f, a, 1.0 - a); + auto a = double2(0.5) * pow(2.0 * select(x < 0.5, x, 1.0 - x), k); + return select(x < 0.5, a, 1.0 - a); } //********************************************************************************************************************** @@ -1001,10 +914,7 @@ static constexpr double3 clamp(double3 v, double3 min, double3 max) noexcept * @brief Clamps vector components between the 0.0 and 1.0. (Inclusive range) * @param v target vector to saturate */ -static constexpr double3 saturate(double3 v) noexcept -{ - return double3(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0), std::clamp(v.z, 0.0, 1.0)); -} +static constexpr double3 saturate(double3 v) noexcept { return double3(saturate(v.x), saturate(v.y), saturate(v.z)); } /*********************************************************************************************************************** * @brief Fused multiply add, calculates: mul1 * mul2 + add @@ -1124,7 +1034,7 @@ static double distance(double3 a, double3 b) noexcept { return length(a - b); } * @param a first vector * @param b second vector */ -static constexpr bool isClose(double3 a, double3 b, double maxDistSq = 1.0e-12f) noexcept +static constexpr bool isClose(double3 a, double3 b, double maxDistSq = 1.0e-28) noexcept { return distanceSq(a, b) <= maxDistSq; } @@ -1140,7 +1050,7 @@ static double3 normalize(double3 v) noexcept { return v * (1.0 / length(v)); } * @param v target vector to check * @param tolerance floating point precision tolerance */ -static bool isNormalized(double3 v, double tolerance = 1.0e-6f) noexcept +static bool isNormalized(double3 v, double tolerance = 1.0e-14) noexcept { return std::abs(lengthSq(v) - 1.0) <= tolerance; } @@ -1163,7 +1073,7 @@ static double3 repeat(double3 v) noexcept { return double3(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static double3 lerp(double3 a, double3 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double3 lerp(double3 a, double3 b, double t) noexcept { return a * (1.0 - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1197,8 +1107,8 @@ static double3 pow(double3 b, double3 e) noexcept */ static double3 gain(double3 x, double3 k) noexcept { - auto a = double3(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); - return select(x < 0.5f, a, 1.0 - a); + auto a = double3(0.5) * pow(2.0 * select(x < 0.5, x, 1.0 - x), k); + return select(x < 0.5, a, 1.0 - a); } //********************************************************************************************************************** @@ -1321,8 +1231,7 @@ static constexpr double4 clamp(double4 v, double4 min, double4 max) noexcept */ static constexpr double4 saturate(double4 v) noexcept { - return double4(std::clamp(v.x, 0.0, 1.0), std::clamp(v.y, 0.0, 1.0), - std::clamp(v.z, 0.0, 1.0), std::clamp(v.w, 0.0, 1.0)); + return double4(saturate(v.x), saturate(v.y), saturate(v.z), saturate(v.w)); } /*********************************************************************************************************************** @@ -1439,7 +1348,7 @@ static double distance(double4 a, double4 b) noexcept { return length(a - b); } * @param a first vector * @param b second vector */ -static constexpr bool isClose(double4 a, double4 b, double maxDistSq = 1.0e-12f) noexcept +static constexpr bool isClose(double4 a, double4 b, double maxDistSq = 1.0e-28) noexcept { return distanceSq(a, b) <= maxDistSq; } @@ -1455,7 +1364,7 @@ static double4 normalize(double4 v) noexcept { return v * (1.0 / length(v)); } * @param v target vector to check * @param tolerance floating point precision tolerance */ -static bool isNormalized(double4 v, double tolerance = 1.0e-6f) noexcept +static bool isNormalized(double4 v, double tolerance = 1.0e-14) noexcept { return std::abs(lengthSq(v) - 1.0) <= tolerance; } @@ -1478,7 +1387,7 @@ static double4 repeat(double4 v) noexcept { return double4(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static double4 lerp(double4 a, double4 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double4 lerp(double4 a, double4 b, double t) noexcept { return a * (1.0 - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1512,8 +1421,8 @@ static double4 pow(double4 b, double4 e) noexcept */ static double4 gain(double4 x, double4 k) noexcept { - auto a = double4(0.5f) * pow(2.0 * select(x < 0.5f, x, 1.0 - x), k); - return select(x < 0.5f, a, 1.0 - a); + auto a = double4(0.5) * pow(2.0 * select(x < 0.5, x, 1.0 - x), k); + return select(x < 0.5, a, 1.0 - a); } //********************************************************************************************************************** diff --git a/include/math/vector/float.hpp b/include/math/vector/float.hpp index 7a33615..eb01eda 100644 --- a/include/math/vector/float.hpp +++ b/include/math/vector/float.hpp @@ -46,50 +46,33 @@ struct [[nodiscard]] float2 * @param y second vector component value */ constexpr float2(float x, float y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr float2(half2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr float2(long2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr float2(ulong2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr float2(int2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ - explicit constexpr float2(uint2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ + + constexpr float2(half4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(half3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(half2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(long4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(long3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(long2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(ulong4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(ulong3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(ulong2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(int4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(int3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(int2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(uint4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(uint3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(uint2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(short4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(short3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } constexpr float2(short2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ + constexpr float2(ushort4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(ushort3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } constexpr float2(ushort2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ + constexpr float2(sbyte4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(sbyte3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } constexpr float2(sbyte2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit floating-point values. - * @param xy first and second vector component value - */ + constexpr float2(byte4 xy) noexcept : x((float)xy.x), y((float)xy.y) { } + constexpr float2(byte3 xy) noexcept : x((float)xy.x), y((float)xy.y) { } constexpr float2(byte2 xy) noexcept : x((float)xy.x), y((float)xy.y) { } /******************************************************************************************************************* @@ -222,50 +205,24 @@ struct [[nodiscard]] float3 * @param yz second and third vector component value */ constexpr float3(float x, float2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr float3(half3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr float3(long3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr float3(ulong3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr float3(int3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ - explicit constexpr float3(uint3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ + + constexpr float3(half4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(half3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(long4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(long3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(ulong4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(ulong3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(int4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(int3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(uint4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(uint3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } + constexpr float3(short4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } constexpr float3(short3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr float3(ushort4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } constexpr float3(ushort3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr float3(sbyte4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } constexpr float3(sbyte3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr float3(byte4 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } constexpr float3(byte3 xyz) noexcept : x((float)xyz.x), y((float)xyz.y), z((float)xyz.z) { } /******************************************************************************************************************* @@ -443,50 +400,15 @@ struct [[nodiscard]] float4 * @param yzw second, third and fourth vector component value */ constexpr float4(float x, float3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr float4(half4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr float4(long4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr float4(ulong4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr float4(int4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ - explicit constexpr float4(uint4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ + + constexpr float4(half4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + constexpr float4(long4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + constexpr float4(ulong4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + constexpr float4(int4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } + constexpr float4(uint4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } constexpr float4(short4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr float4(ushort4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr float4(sbyte4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr float4(byte4 xyzw) noexcept : x((float)xyzw.x), y((float)xyzw.y), z((float)xyzw.z), w((float)xyzw.w) { } /******************************************************************************************************************* @@ -625,7 +547,7 @@ static string toString(float2 v) { return to_string(v.x) + " " + to_string(v.y); * @param a first vector to compare * @param b second vector to compare */ -static uint2 equal(float2 a, float4 b) noexcept +static uint2 equal(float2 a, float2 b) noexcept { return uint2(a.x == b.x ? UINT32_MAX : 0, a.y == b.y ? UINT32_MAX : 0); } @@ -635,7 +557,7 @@ static uint2 equal(float2 a, float4 b) noexcept * @param a first vector to compare * @param b second vector to compare */ -static uint2 notEqual(float2 a, float4 b) noexcept +static uint2 notEqual(float2 a, float2 b) noexcept { return uint2(a.x != b.x ? UINT32_MAX : 0, a.y != b.y ? UINT32_MAX : 0); } @@ -706,10 +628,7 @@ static constexpr float2 clamp(float2 v, float2 min, float2 max) noexcept * @brief Clamps vector components between the 0.0f and 1.0f. (Inclusive range) * @param v target vector to saturate */ -static constexpr float2 saturate(float2 v) noexcept -{ - return float2(std::clamp(v.x, 0.0f, 1.0f), std::clamp(v.y, 0.0f, 1.0f)); -} +static constexpr float2 saturate(float2 v) noexcept { return float2(saturate(v.x), saturate(v.y)); } /*********************************************************************************************************************** * @brief Fused multiply add, calculates: mul1 * mul2 + add @@ -855,7 +774,7 @@ static float2 repeat(float2 v) noexcept { return float2(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static float2 lerp(float2 a, float2 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float2 lerp(float2 a, float2 b, float t) noexcept { return a * (1.0f - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1001,10 +920,7 @@ static constexpr float3 clamp(float3 v, float3 min, float3 max) noexcept * @brief Clamps vector components between the 0.0f and 1.0f. (Inclusive range) * @param v target vector to saturate */ -static constexpr float3 saturate(float3 v) noexcept -{ - return float3(std::clamp(v.x, 0.0f, 1.0f), std::clamp(v.y, 0.0f, 1.0f), std::clamp(v.z, 0.0f, 1.0f)); -} +static constexpr float3 saturate(float3 v) noexcept { return float3(saturate(v.x), saturate(v.y), saturate(v.z)); } /*********************************************************************************************************************** * @brief Fused multiply add, calculates: mul1 * mul2 + add @@ -1163,7 +1079,7 @@ static float3 repeat(float3 v) noexcept { return float3(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static float3 lerp(float3 a, float3 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float3 lerp(float3 a, float3 b, float t) noexcept { return a * (1.0f - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1321,8 +1237,7 @@ static constexpr float4 clamp(float4 v, float4 min, float4 max) noexcept */ static constexpr float4 saturate(float4 v) noexcept { - return float4(std::clamp(v.x, 0.0f, 1.0f), std::clamp(v.y, 0.0f, 1.0f), - std::clamp(v.z, 0.0f, 1.0f), std::clamp(v.w, 0.0f, 1.0f)); + return float4(saturate(v.x), saturate(v.y), saturate(v.z), saturate(v.w)); } /*********************************************************************************************************************** @@ -1478,7 +1393,7 @@ static float4 repeat(float4 v) noexcept { return float4(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static float4 lerp(float4 a, float4 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float4 lerp(float4 a, float4 b, float t) noexcept { return a * (1.0f - t) + b * t; } /** * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! diff --git a/include/math/vector/half.hpp b/include/math/vector/half.hpp index 54b25e7..1989469 100644 --- a/include/math/vector/half.hpp +++ b/include/math/vector/half.hpp @@ -38,7 +38,7 @@ struct [[nodiscard]] half2 * @brief Creates a new 2-component vector of 16-bit floating-point values. * @param xy target value for all vector components */ - constexpr explicit half2(half xy = 0.0f) noexcept : x(xy), y(xy) { } + constexpr explicit half2(half xy = 0.0_hf) noexcept : x(xy), y(xy) { } /** * @brief Creates a new 2-component vector of 16-bit floating-point values. * @@ -46,45 +46,30 @@ struct [[nodiscard]] half2 * @param y second vector component value */ constexpr half2(half x, half y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + + explicit constexpr half2(long4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(long3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(long2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + explicit constexpr half2(ulong4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(ulong3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(ulong2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + explicit constexpr half2(int4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(int3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(int2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + explicit constexpr half2(uint4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(uint3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(uint2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + explicit constexpr half2(short4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(short3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(short2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + explicit constexpr half2(ushort4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + explicit constexpr half2(ushort3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } explicit constexpr half2(ushort2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + constexpr half2(sbyte4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + constexpr half2(sbyte3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } constexpr half2(sbyte2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit floating-point values. - * @param xy first and second vector component value - */ + constexpr half2(byte4 xy) noexcept : x((half)xy.x), y((half)xy.y) { } + constexpr half2(byte3 xy) noexcept : x((half)xy.x), y((half)xy.y) { } constexpr half2(byte2 xy) noexcept : x((half)xy.x), y((half)xy.y) { } /******************************************************************************************************************* @@ -119,21 +104,21 @@ struct [[nodiscard]] half2 epsilon, inf, minusInf, nan, left, right, bottom, top; }; -inline constexpr half2 half2::zero = half2(0.0f); -inline constexpr half2 half2::one = half2(1.0f); -inline constexpr half2 half2::minusOne = half2(-1.0f); +inline constexpr half2 half2::zero = half2(0.0_hf); +inline constexpr half2 half2::one = half2(1.0_hf); +inline constexpr half2 half2::minusOne = half2(-1.0_hf); inline constexpr half2 half2::min = half2(FLT16_MIN); inline constexpr half2 half2::minusMin = half2(-FLT16_MIN); inline constexpr half2 half2::max = half2(FLT16_MAX); inline constexpr half2 half2::minusMax = half2(-FLT16_MAX); inline constexpr half2 half2::epsilon = half2(FLT16_EPSILON); -inline constexpr half2 half2::inf = half2(INFINITY); -inline constexpr half2 half2::minusInf = half2(-INFINITY); -inline constexpr half2 half2::nan = half2(NAN); -inline constexpr half2 half2::left = half2(-1.0f, 0.0f); -inline constexpr half2 half2::right = half2(1.0f, 0.0f); -inline constexpr half2 half2::bottom = half2(0.0f, -1.0f); -inline constexpr half2 half2::top = half2(0.0f, 1.0f); +inline constexpr half2 half2::inf = half2((half)INFINITY); +inline constexpr half2 half2::minusInf = half2((half)-INFINITY); +inline constexpr half2 half2::nan = half2((half)NAN); +inline constexpr half2 half2::left = half2(-1.0_hf, 0.0_hf); +inline constexpr half2 half2::right = half2(1.0_hf, 0.0_hf); +inline constexpr half2 half2::bottom = half2(0.0_hf, -1.0_hf); +inline constexpr half2 half2::top = half2(0.0_hf, 1.0_hf); /*********************************************************************************************************************** * @brief A 3-component vector of 16-bit floating-point values. @@ -149,7 +134,7 @@ struct [[nodiscard]] half3 * @brief Creates a new 3-component vector of 16-bit floating-point values. * @param xyz target value for all vector components */ - constexpr explicit half3(half xyz = 0.0f) noexcept : x(xyz), y(xyz), z(xyz) { } + constexpr explicit half3(half xyz = 0.0_hf) noexcept : x(xyz), y(xyz), z(xyz) { } /** * @brief Creates a new 3-component vector of 16-bit floating-point values. * @@ -172,45 +157,22 @@ struct [[nodiscard]] half3 * @param yz second and third vector component value */ constexpr half3(half x, half2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + + explicit constexpr half3(long4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(long3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + explicit constexpr half3(ulong4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(ulong3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + explicit constexpr half3(int4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(int3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + explicit constexpr half3(uint4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(uint3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + explicit constexpr half3(short4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(short3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + explicit constexpr half3(ushort4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } explicit constexpr half3(ushort3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr half3(sbyte4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } constexpr half3(sbyte3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit floating-point values. - * @param xyz first, second and third vector component value - */ + constexpr half3(byte4 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } constexpr half3(byte3 xyz) noexcept : x((half)xyz.x), y((half)xyz.y), z((half)xyz.z) { } /******************************************************************************************************************* @@ -254,23 +216,23 @@ struct [[nodiscard]] half3 epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; }; -inline constexpr half3 half3::zero = half3(0.0f); -inline constexpr half3 half3::one = half3(1.0f); -inline constexpr half3 half3::minusOne = half3(-1.0f); +inline constexpr half3 half3::zero = half3(0.0_hf); +inline constexpr half3 half3::one = half3(1.0_hf); +inline constexpr half3 half3::minusOne = half3(-1.0_hf); inline constexpr half3 half3::min = half3(FLT16_MIN); inline constexpr half3 half3::minusMin = half3(-FLT16_MIN); inline constexpr half3 half3::max = half3(FLT16_MAX); inline constexpr half3 half3::minusMax = half3(-FLT16_MAX); inline constexpr half3 half3::epsilon = half3(FLT16_EPSILON); -inline constexpr half3 half3::inf = half3(INFINITY); -inline constexpr half3 half3::minusInf = half3(-INFINITY); -inline constexpr half3 half3::nan = half3(NAN); -inline constexpr half3 half3::left = half3(-1.0f, 0.0f, 0.0f); -inline constexpr half3 half3::right = half3(1.0f, 0.0f, 0.0f); -inline constexpr half3 half3::bottom = half3(0.0f, -1.0f, 0.0f); -inline constexpr half3 half3::top = half3(0.0f, 1.0f, 0.0f); -inline constexpr half3 half3::back = half3(0.0f, 0.0f, -1.0f); -inline constexpr half3 half3::front = half3(0.0f, 0.0f, 1.0f); +inline constexpr half3 half3::inf = half3((half)INFINITY); +inline constexpr half3 half3::minusInf = half3((half)-INFINITY); +inline constexpr half3 half3::nan = half3((half)NAN); +inline constexpr half3 half3::left = half3(-1.0_hf, 0.0_hf, 0.0_hf); +inline constexpr half3 half3::right = half3(1.0_hf, 0.0_hf, 0.0_hf); +inline constexpr half3 half3::bottom = half3(0.0_hf, -1.0_hf, 0.0_hf); +inline constexpr half3 half3::top = half3(0.0_hf, 1.0_hf, 0.0_hf); +inline constexpr half3 half3::back = half3(0.0_hf, 0.0_hf, -1.0_hf); +inline constexpr half3 half3::front = half3(0.0_hf, 0.0_hf, 1.0_hf); /*********************************************************************************************************************** * @brief A 4-component vector of 16-bit floating-point values. @@ -287,7 +249,7 @@ struct [[nodiscard]] half4 * @brief Creates a new 4-component vector of 16-bit floating-point values. * @param xyzw target value for all vector components */ - constexpr explicit half4(half xyzw = 0.0f) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } + constexpr explicit half4(half xyzw = 0.0_hf) noexcept : x(xyzw), y(xyzw), z(xyzw), w(xyzw) { } /** * @brief Creates a new 4-component vector of 16-bit floating-point values. * @@ -342,45 +304,14 @@ struct [[nodiscard]] half4 * @param yzw second, third and fourth vector component value */ constexpr half4(half x, half3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ + explicit constexpr half4(long4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ explicit constexpr half4(ulong4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ explicit constexpr half4(int4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ explicit constexpr half4(uint4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ explicit constexpr half4(short4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ explicit constexpr half4(ushort4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr half4(sbyte4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit floating-point values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr half4(byte4 xyzw) noexcept : x((half)xyzw.x), y((half)xyzw.y), z((half)xyzw.z), w((half)xyzw.w) { } /******************************************************************************************************************* @@ -432,16 +363,16 @@ struct [[nodiscard]] half4 static const half4 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan; }; -inline constexpr half4 half4::zero = half4(0.0f); -inline constexpr half4 half4::one = half4(1.0f); -inline constexpr half4 half4::minusOne = half4(-1.0f); +inline constexpr half4 half4::zero = half4(0.0_hf); +inline constexpr half4 half4::one = half4(1.0_hf); +inline constexpr half4 half4::minusOne = half4(-1.0_hf); inline constexpr half4 half4::min = half4(FLT16_MIN); inline constexpr half4 half4::minusMin = half4(-FLT16_MIN); inline constexpr half4 half4::max = half4(FLT16_MAX); inline constexpr half4 half4::minusMax = half4(-FLT16_MAX); inline constexpr half4 half4::epsilon = half4(FLT16_EPSILON); -inline constexpr half4 half4::inf = half4(INFINITY); -inline constexpr half4 half4::minusInf = half4(-INFINITY); -inline constexpr half4 half4::nan = half4(NAN); +inline constexpr half4 half4::inf = half4((half)INFINITY); +inline constexpr half4 half4::minusInf = half4((half)-INFINITY); +inline constexpr half4 half4::nan = half4((half)NAN); } // namespace math \ No newline at end of file diff --git a/include/math/vector/int.hpp b/include/math/vector/int.hpp index 70fc2a9..1518d4b 100644 --- a/include/math/vector/int.hpp +++ b/include/math/vector/int.hpp @@ -19,7 +19,6 @@ */ #pragma once -#include "math/vector/short.hpp" #include "math/vector/uint.hpp" namespace math @@ -46,30 +45,11 @@ struct [[nodiscard]] int2 * @param y second vector component value */ constexpr int2(int32 x, int32 y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 32-bit signed integer values. - * @param xy first and second vector component value - */ + constexpr int2(uint2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit signed integer values. - * @param xy first and second vector component value - */ constexpr int2(short2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit signed integer values. - * @param xy first and second vector component value - */ constexpr int2(ushort2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit signed integer values. - * @param xy first and second vector component value - */ constexpr int2(sbyte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } - /** - * @brief Creates a new 2-component vector of 32-bit signed integer values. - * @param xy first and second vector component value - */ constexpr int2(byte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } /******************************************************************************************************************* @@ -217,30 +197,11 @@ struct [[nodiscard]] int3 * @param yz second and third vector component value */ constexpr int3(int32 x, int2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 32-bit signed integer values. - * @param xyz first, second and third vector component value - */ + constexpr int3(uint3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr int3(short3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr int3(ushort3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr int3(sbyte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 32-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr int3(byte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } /******************************************************************************************************************* @@ -429,30 +390,11 @@ struct [[nodiscard]] int4 * @param[in] yzw second, third and fourth vector component value */ constexpr int4(int32 x, int3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 32-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ + constexpr int4(uint4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr int4(short4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr int4(ushort4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr int4(sbyte4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 32-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr int4(byte4 xyzw) noexcept : x((int32)xyzw.x), y((int32)xyzw.y), z((int32)xyzw.z), w((int32)xyzw.w) { } /******************************************************************************************************************* diff --git a/include/math/vector/long.hpp b/include/math/vector/long.hpp index 32e490b..f50b781 100644 --- a/include/math/vector/long.hpp +++ b/include/math/vector/long.hpp @@ -19,7 +19,6 @@ */ #pragma once -#include "math/vector/int.hpp" #include "math/vector/ulong.hpp" namespace math @@ -46,40 +45,13 @@ struct [[nodiscard]] long2 * @param y second vector component value */ constexpr long2(int64 x, int64 y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ + constexpr long2(ulong2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(int2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(uint2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(short2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(ushort2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(sbyte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } - /** - * @brief Creates a new 2-component vector of 64-bit signed integer values. - * @param xy first and second vector component value - */ constexpr long2(byte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } /******************************************************************************************************************* @@ -229,40 +201,13 @@ struct [[nodiscard]] long3 * @param yz second and third vector component value */ constexpr long3(int64 x, long2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ + constexpr long3(ulong3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(int3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(uint3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(short3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(ushort3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(sbyte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 64-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr long3(byte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } /******************************************************************************************************************* @@ -455,40 +400,13 @@ struct [[nodiscard]] long4 * @param[in] yzw second, third and fourth vector component value */ constexpr long4(int64 x, long3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ + constexpr long4(ulong4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(int4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(uint4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(short4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(ushort4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(sbyte4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 64-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr long4(byte4 xyzw) noexcept : x((int64)xyzw.x), y((int64)xyzw.y), z((int64)xyzw.z), w((int64)xyzw.w) { } /******************************************************************************************************************* diff --git a/include/math/vector/sbyte.hpp b/include/math/vector/sbyte.hpp index f6f3585..7416432 100644 --- a/include/math/vector/sbyte.hpp +++ b/include/math/vector/sbyte.hpp @@ -45,10 +45,7 @@ struct [[nodiscard]] sbyte2 * @param y second vector component value */ constexpr sbyte2(int8 x, int8 y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 8-bit signed integer values. - * @param xyzw first and second vector component value - */ + constexpr sbyte2(byte2 xy) noexcept : x((int8)xy.x), y((int8)xy.y) { } /******************************************************************************************************************* @@ -192,10 +189,7 @@ struct [[nodiscard]] sbyte3 * @param yz second and third vector component value */ constexpr sbyte3(int8 x, sbyte2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 8-bit signed integer values. - * @param xyz first, second and third vector component value - */ + constexpr sbyte3(byte3 xyz) noexcept : x((int8)xyz.x), y((int8)xyz.y), z((int8)xyz.z) { } /******************************************************************************************************************* @@ -376,10 +370,7 @@ struct [[nodiscard]] sbyte4 * @param[in] yzw second, third and fourth vector component value */ constexpr sbyte4(int8 x, sbyte3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 8-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ + constexpr sbyte4(byte4 xyzw) noexcept : x((int8)xyzw.x), y((int8)xyzw.y), z((int8)xyzw.z), w((int8)xyzw.w) { } /******************************************************************************************************************* diff --git a/include/math/vector/short.hpp b/include/math/vector/short.hpp index 9a7248a..54e5f76 100644 --- a/include/math/vector/short.hpp +++ b/include/math/vector/short.hpp @@ -19,7 +19,6 @@ */ #pragma once -#include "math/vector/sbyte.hpp" #include "math/vector/ushort.hpp" namespace math @@ -46,20 +45,9 @@ struct [[nodiscard]] short2 * @param y second vector component value */ constexpr short2(int16 x, int16 y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 16-bit signed integer values. - * @param xy first and second vector component value - */ + constexpr short2(ushort2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit signed integer values. - * @param xy first and second vector component value - */ constexpr short2(sbyte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } - /** - * @brief Creates a new 2-component vector of 16-bit signed integer values. - * @param xy first and second vector component value - */ constexpr short2(byte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } /******************************************************************************************************************* @@ -205,20 +193,9 @@ struct [[nodiscard]] short3 * @param yz second and third vector component value */ constexpr short3(int16 x, short2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 16-bit signed integer values. - * @param xyz first, second and third vector component value - */ + constexpr short3(ushort3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr short3(sbyte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } - /** - * @brief Creates a new 3-component vector of 16-bit signed integer values. - * @param xyz first, second and third vector component value - */ constexpr short3(byte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } /******************************************************************************************************************* @@ -403,20 +380,9 @@ struct [[nodiscard]] short4 * @param[in] yzw second, third and fourth vector component value */ constexpr short4(int16 x, short3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 16-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ + constexpr short4(ushort4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr short4(sbyte4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } - /** - * @brief Creates a new 4-component vector of 16-bit signed integer values. - * @param xyzw first, second, third and fourth vector component value - */ constexpr short4(byte4 xyzw) noexcept : x((int16)xyzw.x), y((int16)xyzw.y), z((int16)xyzw.z), w((int16)xyzw.w) { } /******************************************************************************************************************* diff --git a/include/math/vector/uint.hpp b/include/math/vector/uint.hpp index 63009b7..4be9a56 100644 --- a/include/math/vector/uint.hpp +++ b/include/math/vector/uint.hpp @@ -19,7 +19,7 @@ */ #pragma once -#include "math/vector/ushort.hpp" +#include "math/vector/short.hpp" #include namespace math @@ -49,6 +49,11 @@ struct [[nodiscard]] uint2 */ constexpr uint2(uint32 x, uint32 y) noexcept : x(x), y(y) { } + constexpr uint2(short2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(ushort2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(sbyte2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(byte2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + /** * @brief Returns vector component by index. * @param i target component index @@ -68,6 +73,11 @@ struct [[nodiscard]] uint2 return ((uint32*)this)[i]; } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + //****************************************************************************************************************** constexpr uint2 operator+(uint2 v) const noexcept { return uint2(x + v.x, y + v.y); } constexpr uint2 operator-(uint2 v) const noexcept { return uint2(x - v.x, y - v.y); } @@ -183,6 +193,11 @@ struct [[nodiscard]] uint3 */ constexpr uint3(uint32 x, uint2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr uint3(short3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(ushort3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(sbyte3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(byte3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + /******************************************************************************************************************* * @brief Returns vector component by index. * @param i target component index @@ -202,7 +217,15 @@ struct [[nodiscard]] uint3 return ((uint32*)this)[i]; } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator uint2() const noexcept { return uint2(x, y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr uint3 operator+(uint3 v) const noexcept { return uint3(x + v.x, y + v.y, z + v.z); } @@ -352,6 +375,11 @@ struct [[nodiscard]] uint4 */ constexpr uint4(uint32 x, uint3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + constexpr uint4(short4 xyzw) noexcept : x((uint32)xyzw.x), y((uint32)xyzw.y), z((uint32)xyzw.z), w((uint32)xyzw.w) { } + constexpr uint4(ushort4 xyzw) noexcept : x((uint32)xyzw.x), y((uint32)xyzw.y), z((uint32)xyzw.z), w((uint32)xyzw.w) { } + constexpr uint4(sbyte4 xyzw) noexcept : x((uint32)xyzw.x), y((uint32)xyzw.y), z((uint32)xyzw.z), w((uint32)xyzw.w) { } + constexpr uint4(byte4 xyzw) noexcept : x((uint32)xyzw.x), y((uint32)xyzw.y), z((uint32)xyzw.z), w((uint32)xyzw.w) { } + /******************************************************************************************************************* * @brief Returns vector component by index. * @param i target component index @@ -371,8 +399,20 @@ struct [[nodiscard]] uint4 return ((uint32*)this)[i]; } + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } constexpr explicit operator uint3() const noexcept { return uint3(x, y, z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator uint2() const noexcept { return uint2(x, y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr uint4 operator+(uint4 v) const noexcept { return uint4(x + v.x, y + v.y, z + v.z, w + v.w); } diff --git a/include/math/vector/ulong.hpp b/include/math/vector/ulong.hpp index b50260e..671a454 100644 --- a/include/math/vector/ulong.hpp +++ b/include/math/vector/ulong.hpp @@ -19,7 +19,7 @@ */ #pragma once -#include "math/vector/uint.hpp" +#include "math/vector/int.hpp" namespace math { @@ -48,6 +48,13 @@ struct [[nodiscard]] ulong2 */ constexpr ulong2(uint64 x, uint64 y) noexcept : x(x), y(y) { } + constexpr ulong2(int2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(uint2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(short2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(ushort2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(sbyte2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(byte2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + /** * @brief Returns vector component by index. * @param i target component index @@ -67,6 +74,13 @@ struct [[nodiscard]] ulong2 return ((uint64*)this)[i]; } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + //****************************************************************************************************************** constexpr ulong2 operator+(ulong2 v) const noexcept { return ulong2(x + v.x, y + v.y); } constexpr ulong2 operator-(ulong2 v) const noexcept { return ulong2(x - v.x, y - v.y); } @@ -181,6 +195,13 @@ struct [[nodiscard]] ulong3 */ constexpr ulong3(uint64 x, ulong2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr ulong3(int3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(uint3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(short3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(ushort3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(sbyte3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(byte3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + /******************************************************************************************************************* * @brief Returns vector component by index. * @param i target component index @@ -200,7 +221,19 @@ struct [[nodiscard]] ulong3 return ((uint64*)this)[i]; } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator ulong2() const noexcept { return ulong2(x, y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr ulong3 operator+(ulong3 v) const noexcept { return ulong3(x + v.x, y + v.y, z + v.z); } @@ -350,6 +383,13 @@ struct [[nodiscard]] ulong4 */ constexpr ulong4(uint64 x, ulong3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } + constexpr ulong4(int4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + constexpr ulong4(uint4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + constexpr ulong4(short4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + constexpr ulong4(ushort4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + constexpr ulong4(sbyte4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + constexpr ulong4(byte4 xyzw) noexcept : x((uint64)xyzw.x), y((uint64)xyzw.y), z((uint64)xyzw.z), w((uint64)xyzw.w) { } + /******************************************************************************************************************* * @brief Returns vector component by index. * @param i target component index @@ -369,8 +409,26 @@ struct [[nodiscard]] ulong4 return ((uint64*)this)[i]; } + constexpr explicit operator int4() const noexcept { return int4((int32)x, (int32)y, (int32)z, (int32)w); } + constexpr explicit operator uint4() const noexcept { return uint4((uint32)x, (uint32)y, (uint32)z, (uint32)w); } + constexpr explicit operator short4() const noexcept { return short4((int16)x, (int16)y, (int16)z, (int16)w); } + constexpr explicit operator ushort4() const noexcept { return ushort4((uint16)x, (uint16)y, (uint16)z, (uint16)w); } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } constexpr explicit operator ulong3() const noexcept { return ulong3(x, y, z); } + constexpr explicit operator int3() const noexcept { return int3((int32)x, (int32)y, (int32)z); } + constexpr explicit operator uint3() const noexcept { return uint3((uint32)x, (uint32)y, (uint32)z); } + constexpr explicit operator short3() const noexcept { return short3((int16)x, (int16)y, (int16)z); } + constexpr explicit operator ushort3() const noexcept { return ushort3((uint16)x, (uint16)y, (uint16)z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator ulong2() const noexcept { return ulong2(x, y); } + constexpr explicit operator int2() const noexcept { return int2((int32)x, (int32)y); } + constexpr explicit operator uint2() const noexcept { return uint2((uint32)x, (uint32)y); } + constexpr explicit operator short2() const noexcept { return short2((int16)x, (int16)y); } + constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr ulong4 operator+(ulong4 v) const noexcept { return ulong4(x + v.x, y + v.y, z + v.z, w + v.w); } diff --git a/include/math/vector/ushort.hpp b/include/math/vector/ushort.hpp index 1e44b99..f03fe02 100644 --- a/include/math/vector/ushort.hpp +++ b/include/math/vector/ushort.hpp @@ -19,7 +19,7 @@ */ #pragma once -#include "math/vector/byte.hpp" +#include "math/vector/sbyte.hpp" namespace math { @@ -47,10 +47,8 @@ struct [[nodiscard]] ushort2 * @param y second vector component value */ constexpr ushort2(uint16 x, uint16 y) noexcept : x(x), y(y) { } - /** - * @brief Creates a new 2-component vector of 16-bit unsigned integer values. - * @param xy first and second vector component value - */ + + constexpr ushort2(sbyte2 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } constexpr ushort2(byte2 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } /** @@ -72,6 +70,9 @@ struct [[nodiscard]] ushort2 return ((uint16*)this)[i]; } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + //****************************************************************************************************************** constexpr ushort2 operator+(ushort2 v) const noexcept { return ushort2(x + v.x, y + v.y); } constexpr ushort2 operator-(ushort2 v) const noexcept { return ushort2(x - v.x, y - v.y); } @@ -186,10 +187,8 @@ struct [[nodiscard]] ushort3 * @param yz second and third vector component value */ constexpr ushort3(uint16 x, ushort2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } - /** - * @brief Creates a new 3-component vector of 16-bit unsigned integer values. - * @param xyz first, second and third vector component value - */ + + constexpr ushort3(sbyte3 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } constexpr ushort3(byte3 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } /******************************************************************************************************************* @@ -211,7 +210,11 @@ struct [[nodiscard]] ushort3 return ((uint16*)this)[i]; } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator ushort2() const noexcept { return ushort2(x, y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr ushort3 operator+(ushort3 v) const noexcept { return ushort3(x + v.x, y + v.y, z + v.z); } @@ -360,10 +363,8 @@ struct [[nodiscard]] ushort4 * @param yzw second, third and fourth vector component value */ constexpr ushort4(uint16 x, ushort3 yzw) noexcept : x(x), y(yzw.x), z(yzw.y), w(yzw.z) { } - /** - * @brief Creates a new 4-component vector of 16-bit unsigned integer values. - * @param xyzw first, second, third and fourth vector component value - */ + + constexpr ushort4(sbyte4 xyzw) noexcept : x((uint16)xyzw.x), y((uint16)xyzw.y), z((uint16)xyzw.z), w((uint16)xyzw.w) { } constexpr ushort4(byte4 xyzw) noexcept : x((uint16)xyzw.x), y((uint16)xyzw.y), z((uint16)xyzw.z), w((uint16)xyzw.w) { } /******************************************************************************************************************* @@ -385,8 +386,14 @@ struct [[nodiscard]] ushort4 return ((uint16*)this)[i]; } + constexpr explicit operator sbyte4() const noexcept { return sbyte4((int8)x, (int8)y, (int8)z, (int8)w); } + constexpr explicit operator byte4() const noexcept { return byte4((uint8)x, (uint8)y, (uint8)z, (uint8)w); } constexpr explicit operator ushort3() const noexcept { return ushort3(x, y, z); } + constexpr explicit operator sbyte3() const noexcept { return sbyte3((int8)x, (int8)y, (int8)z); } + constexpr explicit operator byte3() const noexcept { return byte3((uint8)x, (uint8)y, (uint8)z); } constexpr explicit operator ushort2() const noexcept { return ushort2(x, y); } + constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } + constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } //****************************************************************************************************************** constexpr ushort4 operator+(ushort4 v) const noexcept { return ushort4(x + v.x, y + v.y, z + v.z, w + v.w); } From f922c14c9543c5a6f883db6cc6642cb8873fa3ec Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 20:16:05 +0300 Subject: [PATCH 03/14] Improvements and fixes --- include/math/color.hpp | 57 ++++++++++++++++++++------ include/math/common.hpp | 39 +++++++++++------- include/math/matrix/float.hpp | 14 +++---- include/math/simd/vector/float.hpp | 34 +++++++++------- include/math/simd/vector/half.hpp | 55 ++++++++++++++++++++++++- include/math/simd/vector/int.hpp | 5 +++ include/math/simd/vector/uint.hpp | 5 +++ include/math/vector/double.hpp | 65 +++++++++++++++++++----------- include/math/vector/float.hpp | 33 ++++++--------- include/math/vector/half.hpp | 18 +++++++++ include/math/vector/int.hpp | 15 +++++++ include/math/vector/long.hpp | 21 ++++++++++ include/math/vector/sbyte.hpp | 3 ++ include/math/vector/short.hpp | 9 +++++ include/math/vector/uint.hpp | 12 ++++++ include/math/vector/ulong.hpp | 18 +++++++++ include/math/vector/ushort.hpp | 6 +++ 17 files changed, 313 insertions(+), 96 deletions(-) diff --git a/include/math/color.hpp b/include/math/color.hpp index 5764108..37a62f5 100644 --- a/include/math/color.hpp +++ b/include/math/color.hpp @@ -170,25 +170,33 @@ struct [[nodiscard]] Color } /******************************************************************************************************************* - * @brief Converts sRGB color to the normalized RG vector. (Red, Green) + * @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha) */ - constexpr explicit operator float2() const noexcept { return float2(r, g) * (1.0f / 255.0f); } + explicit operator f32x4() const noexcept { return f32x4(r, g, b, a) * (1.0f / 255.0f); } /** - * @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue) + * @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha) */ - constexpr explicit operator float3() const noexcept { return float3(r, g, b) * (1.0f / 255.0f); } + explicit operator f16x4() const noexcept { return (f16x4)(f32x4(r, g, b, a) * (1.0f / 255.0f)); } /** * @brief Converts sRGB color to the normalized RGBA vector. (Red, Green, Blue, Alpha) */ constexpr explicit operator float4() const noexcept { return float4(r, g, b, a) * (1.0f / 255.0f); } /** - * @brief Converts sRGB color to the normalized RGBA SIMD vector. (Red, Green, Blue, Alpha) + * @brief Converts sRGB color to the normalized RGBA vector. (Red, Green, Blue, Alpha) */ - explicit operator f32x4() const noexcept { return f32x4(r, g, b, a) * (1.0f / 255.0f); } + constexpr explicit operator half4() const noexcept { return (half4)(float4(r, g, b, a) * (1.0f / 255.0f)); } /** * @brief Returns color as binary vector. */ explicit operator byte4() const noexcept { return *((const byte4*)this); } + /** + * @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue) + */ + constexpr explicit operator float3() const noexcept { return float3(r, g, b) * (1.0f / 255.0f); } + /** + * @brief Converts sRGB color to the normalized RGB vector. (Red, Green, Blue) + */ + constexpr explicit operator half3() const noexcept { return (half3)(float3(r, g, b) * (1.0f / 255.0f)); } /** * @brief Returns color as unsigned integer value */ @@ -302,6 +310,16 @@ static constexpr bool operator>(uint8 n, Color c) noexcept { return Color(n) > c static constexpr bool operator<=(uint8 n, Color c) noexcept { return Color(n) <= c; } static constexpr bool operator>=(uint8 n, Color c) noexcept { return Color(n) >= c; } +/** + * @brief Creates a new sRGB color. (CSS style declaration) + * + * @param r red channel color value + * @param g green channel color value + * @param b blue channel color value + * @param a alpha channel color value (transparency) + */ +static constexpr Color rgba(uint8 r, uint8 g, uint8 b, float a) noexcept { return Color(Color(r, g, b), a); } + /** * @brief Returns true if first color binary representation is less than the second. * @@ -310,15 +328,30 @@ static constexpr bool operator>=(uint8 n, Color c) noexcept { return Color(n) >= */ static bool isBinaryLess(Color a, Color b) noexcept { return *((const uint32*)&a) < *((const uint32*)&b); } +/*********************************************************************************************************************** + * @brief Linearly interpolates each component of the color between a and b using t. + * + * @param a minimum color (t == 0.0) + * @param b maximum color (t == 1.0) + * @param t target interpolation value (0.0 - 1.0) + */ +static Color lerp(Color a, Color b, float t) noexcept +{ + return Color::fromLinear(lerp(a.toLinear(), b.toLinear(), t)); +} /** - * @brief Creates a new sRGB color. (CSS style declaration) + * @brief Linearly interpolates each component of the color between a and b taking into account delta time. + * @note Always use this function instead of basic lerp() when you have variable delta time! * - * @param r red channel color value - * @param g green channel color value - * @param b blue channel color value - * @param a alpha channel color value (transparency) + * @param a minimum color (t == 0.0) + * @param b maximum color (t == 1.0) + * @param dr target decay rate value + * @param dt current delta time value */ -static constexpr Color rgba(uint8 r, uint8 g, uint8 b, float a) noexcept { return Color(Color(r, g, b), a); } +static Color lerpDelta(Color a, Color b, float dr, float dt) noexcept +{ + return Color::fromLinear(lerpDelta(a.toLinear(), b.toLinear(), dr, dt)); +} // TODO: color conversion functions. diff --git a/include/math/common.hpp b/include/math/common.hpp index 71260a8..0a38f41 100644 --- a/include/math/common.hpp +++ b/include/math/common.hpp @@ -27,6 +27,8 @@ namespace math using namespace std; +#define M_LN100 4.60517018598809136803598290936872842 // loge(100) + /** * @brief Returns the minimum of three values. * @@ -70,7 +72,7 @@ static float sign(float v) noexcept { return std::signbit(v) ? -1.0f : 1.0f; } */ static double sign(double v) noexcept { return std::signbit(v) ? -1.0 : 1.0; } -/** +/*********************************************************************************************************************** * @brief Remaps specified value to the 0.0 - 1.0 range. * @param v target floating-point value to repeat */ @@ -102,7 +104,7 @@ static double repeat(double v) noexcept * @param b maximum value (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float lerp(float a, float b, float t) noexcept { return a + t * (b - a); } +static constexpr float lerp(float a, float b, float t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } /** * @brief Linearly interpolates between a and b values using t. * @@ -110,36 +112,43 @@ static constexpr float lerp(float a, float b, float t) noexcept { return a + t * * @param b maximum value (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double lerp(double a, double b, double t) noexcept { return a + t * (b - a); } +static constexpr double lerp(double a, double b, double t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } /** - * @brief Linearly interpolates between a and b values using t, taking into account delta time. + * @brief Linearly interpolates between a and b values taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum value (t == 0.0) * @param b maximum value (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static float lerpDelta(float a, float b, float f, float dt) noexcept -{ - return a + (1.0f - std::pow(f, dt)) * (b - a); -} +static float lerpDelta(float a, float b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** - * @brief Linearly interpolates between a and b values using t, taking into account delta time. + * @brief Linearly interpolates between a and b values taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum value (t == 0.0) * @param b maximum value (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static double lerpDelta(double a, double b, double f, double dt) noexcept -{ - return a + (1.0 - std::pow(f, dt)) * (b - a); -} +static double lerpDelta(double a, double b, double dr, double dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** + * @brief Converts seconds needed to reach 99% of the distance to the decay rate. + * @details Use this function to calculate dt parameter for the lerpDelta(). + * @param time target time to convert in seconds + */ +static constexpr float secToDecRate(float time) noexcept { return (float)M_LN100 / time; } +/** + * @brief Converts seconds needed to reach 99% of the distance to the decay rate. + * @details Use this function to calculate dt parameter for the lerpDelta(). + * @param time target time to convert in seconds + */ +static constexpr double secToDecRate(double time) noexcept { return M_LN100 / time; } + +/*********************************************************************************************************************** * @brief Applies gain function to the x value. * @note The function is symmetric when x == 0.5. * diff --git a/include/math/matrix/float.hpp b/include/math/matrix/float.hpp index 3c14a03..39b7169 100644 --- a/include/math/matrix/float.hpp +++ b/include/math/matrix/float.hpp @@ -112,18 +112,18 @@ struct [[nodiscard]] float2x2 * @brief Calculates dot product between two matrices. * @param[in] m target matrix to dot by */ - float2x2& operator*=(const float2x2& m) noexcept { return *this = *this * m; } + float2x2& operator*=(float2x2 m) noexcept { return *this = *this * m; } /** * @brief Returns true if matrices have the same values. * @param[in] m another matrix to compare with */ - bool operator==(const float2x2& m) const noexcept { return memcmp(this, &m, sizeof(float2x2)) == 0; } + bool operator==(float2x2 m) const noexcept { return memcmp(this, &m, sizeof(float2x2)) == 0; } /** * @brief Returns true if matrices have different values. * @param[in] m another matrix to compare with */ - bool operator!=(const float2x2& m) const noexcept { return memcmp(this, &m, sizeof(float2x2)) != 0; } + bool operator!=(float2x2 m) const noexcept { return memcmp(this, &m, sizeof(float2x2)) != 0; } static const float2x2 zero, one, minusOne, identity; }; @@ -646,10 +646,10 @@ static constexpr float3x3 operator-(float n, const float3x3& m) noexcept { retur static constexpr float3x3 operator*(float n, const float3x3& m) noexcept { return float3x3(n * m.c0, n * m.c1, n * m.c2); } static constexpr float3x3 operator/(float n, const float3x3& m) noexcept { return float3x3(n / m.c0, n / m.c1, n / m.c2); } -static constexpr float2x2 operator+(float n, const float2x2& m) noexcept { return float2x2(n + m.c0, n + m.c1); } -static constexpr float2x2 operator-(float n, const float2x2& m) noexcept { return float2x2(n - m.c0, n - m.c1); } -static constexpr float2x2 operator*(float n, const float2x2& m) noexcept { return float2x2(n * m.c0, n * m.c1); } -static constexpr float2x2 operator/(float n, const float2x2& m) noexcept { return float2x2(n / m.c0, n / m.c1); } +static constexpr float2x2 operator+(float n, float2x2 m) noexcept { return float2x2(n + m.c0, n + m.c1); } +static constexpr float2x2 operator-(float n, float2x2 m) noexcept { return float2x2(n - m.c0, n - m.c1); } +static constexpr float2x2 operator*(float n, float2x2 m) noexcept { return float2x2(n * m.c0, n * m.c1); } +static constexpr float2x2 operator/(float n, float2x2 m) noexcept { return float2x2(n / m.c0, n / m.c1); } /*********************************************************************************************************************** * @brief Calculates dot product between vector and matrix. diff --git a/include/math/simd/vector/float.hpp b/include/math/simd/vector/float.hpp index b2e460f..9a5bfc6 100644 --- a/include/math/simd/vector/float.hpp +++ b/include/math/simd/vector/float.hpp @@ -31,10 +31,6 @@ namespace math { -struct [[nodiscard]] f32x4; -static u32x4 floatAsUint(f32x4 v) noexcept; -static f32x4 uintAsFloat(u32x4 v) noexcept; - /** * @brief A 4-component SIMD vector of 32-bit floating-point values. (float4) * @details Commonly used to represent: points, positions, directions, velocities, etc. @@ -156,7 +152,7 @@ struct [[nodiscard]] f32x4 #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvtq_f32_u32(v.data); #else - floats = v.floats; + floats = (float4)v.uints; #endif } explicit f32x4(i32x4 v) noexcept @@ -166,7 +162,7 @@ struct [[nodiscard]] f32x4 #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvtq_f32_s32(v.data); #else - floats = v.floats; + floats = (float4)v.ints; #endif } @@ -214,6 +210,7 @@ struct [[nodiscard]] f32x4 #endif } + explicit f32x4(double4 v) noexcept { *this = (f32x4)float4(v); } explicit f32x4(half4 v) noexcept { *this = (f32x4)f16x4(v); } explicit f32x4(long4 v) noexcept { *this = (f32x4)float4(v); } explicit f32x4(ulong4 v) noexcept { *this = (f32x4)float4(v); } @@ -223,6 +220,7 @@ struct [[nodiscard]] f32x4 explicit f32x4(ushort4 v) noexcept { *this = (f32x4)float4(v); } explicit f32x4(sbyte4 v) noexcept { *this = (f32x4)float4(v); } explicit f32x4(byte4 v) noexcept { *this = (f32x4)float4(v); } + explicit f32x4(double3 v) noexcept { *this = (f32x4)float3(v); } explicit f32x4(half3 v) noexcept { *this = (f32x4)f16x4(v); } explicit f32x4(long3 v) noexcept { *this = (f32x4)float3(v); } explicit f32x4(ulong3 v) noexcept { *this = (f32x4)float3(v); } @@ -440,6 +438,7 @@ struct [[nodiscard]] f32x4 #endif } + explicit operator double4() const noexcept { return (double4)floats; } explicit operator float4() const noexcept { return floats; } explicit operator half4() const noexcept { return (half4)floats; } explicit operator long4() const noexcept { return (long4)floats; } @@ -450,6 +449,7 @@ struct [[nodiscard]] f32x4 explicit operator ushort4() const noexcept { return (ushort4)floats; } explicit operator sbyte4() const noexcept { return (sbyte4)floats; } explicit operator byte4() const noexcept { return (byte4)floats; } + explicit operator double3() const noexcept { return (double3)floats; } explicit operator float3() const noexcept { return (float3)floats; } explicit operator half3() const noexcept { return (half3)floats; } explicit operator long3() const noexcept { return (long3)floats; } @@ -460,6 +460,7 @@ struct [[nodiscard]] f32x4 explicit operator ushort3() const noexcept { return (ushort3)floats; } explicit operator sbyte3() const noexcept { return (sbyte3)floats; } explicit operator byte3() const noexcept { return (byte3)floats; } + explicit operator double2() const noexcept { return (double2)floats; } explicit operator float2() const noexcept { return (float2)floats; } explicit operator half2() const noexcept { return (half2)floats; } explicit operator long2() const noexcept { return (long2)floats; } @@ -514,7 +515,13 @@ struct [[nodiscard]] f32x4 } f32x4 operator^(f32x4 v) const noexcept { - return uintAsFloat(floatAsUint(*this) ^ floatAsUint(v)); + #if defined(MATH_SIMD_SUPPORT_SSE) + return _mm_xor_ps(data, v.data); + #elif defined(MATH_SIMD_SUPPORT_NEON) + return vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(data), vreinterpretq_u32_f32(v.data))); + #else + return *((const f32x4*)(*((const u32x4*)this) ^ *((const u32x4*)&v))); + #endif } f32x4 operator-() const noexcept { @@ -1487,20 +1494,17 @@ static f32x4 repeat(f32x4 v) noexcept * @param b maximum SIMD vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static f32x4 lerp(f32x4 a, f32x4 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static f32x4 lerp(f32x4 a, f32x4 b, float t) noexcept { return fma(f32x4(t), b, fma(f32x4(-t), a, a)); } /** - * @brief Linearly interpolates each component of the SIMD vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the SIMD vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum SIMD vector (t == 0.0) * @param b maximum SIMD vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) - * @param dt current delta time + * @param dr target decay rate value + * @param dt current delta time value */ -static f32x4 lerpDelta(f32x4 a, f32x4 b, float f, float dt) noexcept -{ - return a + (1.0f - std::pow(f, dt)) * (b - a); -} +static f32x4 lerpDelta(f32x4 a, f32x4 b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /*********************************************************************************************************************** * @brief Compresses 4D SIMD unit vector into the 4 byte value. diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index 6c012ce..cd826f2 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -18,7 +18,7 @@ */ #pragma once -#include "math/vector/float.hpp" +#include "math/vector/double.hpp" #include "math/simd/vector/int.hpp" #if defined(MATH_SIMD_SUPPORT_AVX2) || defined(MATH_SIMD_SUPPORT_NEON) || defined(FLT16_MIN) @@ -128,6 +128,27 @@ struct [[nodiscard]] f16x4 f16x4(_simd_f64 data) noexcept : data(data) { } #endif + explicit f16x4(u32x4 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_SSE) + data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = vcvt_f32_f16(vcvtq_f32_u32(v.data)); + #else + halfs = (half4)v.uints; + #endif + } + explicit f16x4(i32x4 v) noexcept + { + #if defined(MATH_SIMD_SUPPORT_SSE) + data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); + #elif defined(MATH_SIMD_SUPPORT_NEON) + data = vcvt_f32_f16(vcvtq_f32_s32(v.data)); + #else + halfs = (half4)v.ints; + #endif + } + /******************************************************************************************************************* * @brief Creates a new 4-component SIMD vector of 16-bit floating-point values. (half4) * @param v target 4 component vector value @@ -158,6 +179,7 @@ struct [[nodiscard]] f16x4 #endif } + explicit f16x4(double4 v) noexcept { *this = (f16x4)half4(v); } explicit f16x4(float4 v) noexcept { *this = (f16x4)half4(v); } explicit f16x4(long4 v) noexcept { *this = (f16x4)half4(v); } explicit f16x4(ulong4 v) noexcept { *this = (f16x4)half4(v); } @@ -167,6 +189,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(ushort4 v) noexcept { *this = (f16x4)half4(v); } explicit f16x4(sbyte4 v) noexcept { *this = (f16x4)half4(v); } explicit f16x4(byte4 v) noexcept { *this = (f16x4)half4(v); } + explicit f16x4(double3 v) noexcept { *this = (f16x4)half3(v); } explicit f16x4(float3 v) noexcept { *this = (f16x4)half3(v); } explicit f16x4(long3 v) noexcept { *this = (f16x4)half3(v); } explicit f16x4(ulong3 v) noexcept { *this = (f16x4)half3(v); } @@ -232,6 +255,7 @@ struct [[nodiscard]] f16x4 */ half operator[](psize i) const noexcept { return halfs[i]; } + explicit operator double4() const noexcept { return (double4)halfs; } explicit operator float4() const noexcept { return (float4)halfs; } explicit operator half4() const noexcept { return halfs; } explicit operator long4() const noexcept { return (long4)halfs; } @@ -242,6 +266,7 @@ struct [[nodiscard]] f16x4 explicit operator ushort4() const noexcept { return (ushort4)halfs; } explicit operator sbyte4() const noexcept { return (sbyte4)halfs; } explicit operator byte4() const noexcept { return (byte4)halfs; } + explicit operator double3() const noexcept { return (double3)halfs; } explicit operator float3() const noexcept { return (float3)halfs; } explicit operator half3() const noexcept { return (half3)halfs; } explicit operator long3() const noexcept { return (long3)halfs; } @@ -252,6 +277,7 @@ struct [[nodiscard]] f16x4 explicit operator ushort3() const noexcept { return (ushort3)halfs; } explicit operator sbyte3() const noexcept { return (sbyte3)halfs; } explicit operator byte3() const noexcept { return (byte3)halfs; } + explicit operator double2() const noexcept { return (double2)halfs; } explicit operator float2() const noexcept { return (float2)halfs; } explicit operator half2() const noexcept { return (half2)halfs; } explicit operator long2() const noexcept { return (long2)halfs; } @@ -263,7 +289,32 @@ struct [[nodiscard]] f16x4 explicit operator sbyte2() const noexcept { return (sbyte2)halfs; } explicit operator byte2() const noexcept { return (byte2)halfs; } - // TODO: math functions after adding AVX512 support. + // TODO: math functions after adding AVX512 / AVX10 support. + + //****************************************************************************************************************** + bool operator==(f16x4 v) const noexcept + { + #if defined(MATH_SIMD_SUPPORT_SSE) + return _mm_movemask_epi8(_mm_cmpeq_epi32(data, v.data)) == 0xFFFF; + #elif defined(MATH_SIMD_SUPPORT_NEON) + return vminv_u16(vceq_f16(data, v.data)) == 0xFFFFFFFFu; + #else + return halfs == v.halfs; + #endif + } + bool operator!=(f16x4 v) const noexcept + { + #if defined(MATH_SIMD_SUPPORT_SSE) + return _mm_movemask_epi8(_mm_cmpeq_epi32(data, v.data)) != 0xFFFF; + #elif defined(MATH_SIMD_SUPPORT_NEON) + return vminv_u16(vceq_f16(data, v.data)) == 0u; + #else + return halfs != v.halfs; + #endif + } + + bool operator==(half n) const noexcept { return *this == f16x4(n); } + bool operator!=(half n) const noexcept { return *this != f16x4(n); } static const f16x4 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; diff --git a/include/math/simd/vector/int.hpp b/include/math/simd/vector/int.hpp index ac448ec..61f74a2 100644 --- a/include/math/simd/vector/int.hpp +++ b/include/math/simd/vector/int.hpp @@ -181,6 +181,7 @@ struct [[nodiscard]] i32x4 #endif } + explicit i32x4(double4 v) noexcept { *this = (i32x4)int4(v); } explicit i32x4(float4 v) noexcept { *this = (i32x4)int4(v); } explicit i32x4(half4 v) noexcept { *this = (i32x4)int4(v); } explicit i32x4(long4 v) noexcept { *this = (i32x4)int4(v); } @@ -190,6 +191,7 @@ struct [[nodiscard]] i32x4 explicit i32x4(ushort4 v) noexcept { *this = (i32x4)int4(v); } explicit i32x4(sbyte4 v) noexcept { *this = (i32x4)int4(v); } explicit i32x4(byte4 v) noexcept { *this = (i32x4)int4(v); } + explicit i32x4(double3 v) noexcept { *this = (i32x4)int3(v); } explicit i32x4(float3 v) noexcept { *this = (i32x4)int3(v); } explicit i32x4(half3 v) noexcept { *this = (i32x4)int3(v); } explicit i32x4(long3 v) noexcept { *this = (i32x4)int3(v); } @@ -372,6 +374,7 @@ struct [[nodiscard]] i32x4 #endif } + explicit operator double4() const noexcept { return (double4)ints; } explicit operator float4() const noexcept { return (float4)ints; } explicit operator half4() const noexcept { return (half4)ints; } explicit operator long4() const noexcept { return (long4)ints; } @@ -382,6 +385,7 @@ struct [[nodiscard]] i32x4 explicit operator ushort4() const noexcept { return (ushort4)ints; } explicit operator sbyte4() const noexcept { return (sbyte4)ints; } explicit operator byte4() const noexcept { return (byte4)ints; } + explicit operator double3() const noexcept { return (double3)ints; } explicit operator float3() const noexcept { return (float3)ints; } explicit operator half3() const noexcept { return (half3)ints; } explicit operator long3() const noexcept { return (long3)ints; } @@ -392,6 +396,7 @@ struct [[nodiscard]] i32x4 explicit operator ushort3() const noexcept { return (ushort3)ints; } explicit operator sbyte3() const noexcept { return (sbyte3)ints; } explicit operator byte3() const noexcept { return (byte3)ints; } + explicit operator double2() const noexcept { return (double2)ints; } explicit operator float2() const noexcept { return (float2)ints; } explicit operator half2() const noexcept { return (half2)ints; } explicit operator long2() const noexcept { return (long2)ints; } diff --git a/include/math/simd/vector/uint.hpp b/include/math/simd/vector/uint.hpp index 265968a..a5d4525 100644 --- a/include/math/simd/vector/uint.hpp +++ b/include/math/simd/vector/uint.hpp @@ -177,6 +177,7 @@ struct [[nodiscard]] u32x4 #endif } + explicit u32x4(double4 v) noexcept { *this = (u32x4)uint4(v); } explicit u32x4(float4 v) noexcept { *this = (u32x4)uint4(v); } explicit u32x4(half4 v) noexcept { *this = (u32x4)uint4(v); } explicit u32x4(long4 v) noexcept { *this = (u32x4)uint4(v); } @@ -186,6 +187,7 @@ struct [[nodiscard]] u32x4 explicit u32x4(ushort4 v) noexcept { *this = (u32x4)uint4(v); } explicit u32x4(sbyte4 v) noexcept { *this = (u32x4)uint4(v); } explicit u32x4(byte4 v) noexcept { *this = (u32x4)uint4(v); } + explicit u32x4(double3 v) noexcept { *this = (u32x4)uint3(v); } explicit u32x4(float3 v) noexcept { *this = (u32x4)uint3(v); } explicit u32x4(half3 v) noexcept { *this = (u32x4)uint3(v); } explicit u32x4(long3 v) noexcept { *this = (u32x4)uint3(v); } @@ -357,6 +359,7 @@ struct [[nodiscard]] u32x4 */ uint32 operator[](psize i) const noexcept { return uints[i]; } + explicit operator double4() const noexcept { return (double4)uints; } explicit operator float4() const noexcept { return (float4)uints; } explicit operator half4() const noexcept { return (half4)uints; } explicit operator long4() const noexcept { return (long4)uints; } @@ -367,6 +370,7 @@ struct [[nodiscard]] u32x4 explicit operator ushort4() const noexcept { return (ushort4)uints; } explicit operator sbyte4() const noexcept { return (sbyte4)uints; } explicit operator byte4() const noexcept { return (byte4)uints; } + explicit operator double3() const noexcept { return (double3)uints; } explicit operator float3() const noexcept { return (float3)uints; } explicit operator half3() const noexcept { return (half3)uints; } explicit operator long3() const noexcept { return (long3)uints; } @@ -377,6 +381,7 @@ struct [[nodiscard]] u32x4 explicit operator ushort3() const noexcept { return (ushort3)uints; } explicit operator sbyte3() const noexcept { return (sbyte3)uints; } explicit operator byte3() const noexcept { return (byte3)uints; } + explicit operator double2() const noexcept { return (double2)uints; } explicit operator float2() const noexcept { return (float2)uints; } explicit operator half2() const noexcept { return (half2)uints; } explicit operator long2() const noexcept { return (long2)uints; } diff --git a/include/math/vector/double.hpp b/include/math/vector/double.hpp index cc2a97d..05af3ff 100644 --- a/include/math/vector/double.hpp +++ b/include/math/vector/double.hpp @@ -46,15 +46,35 @@ struct [[nodiscard]] double2 */ constexpr double2(double x, double y) noexcept : x(x), y(y) { } + constexpr double2(float4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(float3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(float2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(half4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(half3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(half2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(long4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(long3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(long2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(ulong4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(ulong3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(ulong2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(int4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(int3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(int2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(uint4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(uint3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(uint2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(short4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(short3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(short2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(ushort4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(ushort3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(ushort2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(sbyte4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(sbyte3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(sbyte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(byte4 xy) noexcept : x((double)xy.x), y((double)xy.y) { } + constexpr double2(byte3 xy) noexcept : x((double)xy.x), y((double)xy.y) { } constexpr double2(byte2 xy) noexcept : x((double)xy.x), y((double)xy.y) { } /******************************************************************************************************************* @@ -86,9 +106,6 @@ struct [[nodiscard]] double2 constexpr explicit operator ushort2() const noexcept { return ushort2((uint16)x, (uint16)y); } constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } - - // TODO: 2/3 overrides, also add missing doubleX conversions in other files. - // Also looks like we will need to add 2/3 overrides also for all integer vector types. //****************************************************************************************************************** constexpr double2 operator+(double2 v) const noexcept { return double2(x + v.x, y + v.y); } @@ -768,20 +785,20 @@ static double2 repeat(double2 v) noexcept { return double2(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double2 lerp(double2 a, double2 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double2 lerp(double2 a, double2 b, double t) noexcept +{ + return fma(double2(t), b, fma(double2(-t), a, a)); +} /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static double2 lerpDelta(double2 a, double2 b, double f, double dt) noexcept -{ - return a + (1.0 - std::pow(f, dt)) * (b - a); -} +static double2 lerpDelta(double2 a, double2 b, double dr, double dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. @@ -1073,20 +1090,20 @@ static double3 repeat(double3 v) noexcept { return double3(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double3 lerp(double3 a, double3 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double3 lerp(double3 a, double3 b, double t) noexcept +{ + return fma(double3(t), b, fma(double3(-t), a, a)); +} /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static double3 lerpDelta(double3 a, double3 b, double f, double dt) noexcept -{ - return a + (1.0 - std::pow(f, dt)) * (b - a); -} +static double3 lerpDelta(double3 a, double3 b, double dr, double dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. @@ -1387,20 +1404,20 @@ static double4 repeat(double4 v) noexcept { return double4(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double4 lerp(double4 a, double4 b, double t) noexcept { return a * (1.0 - t) + b * t; } +static constexpr double4 lerp(double4 a, double4 b, double t) noexcept +{ + return fma(double4(t), b, fma(double4(-t), a, a)); +} /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static double4 lerpDelta(double4 a, double4 b, double f, double dt) noexcept -{ - return a + (1.0 - std::pow(f, dt)) * (b - a); -} +static double4 lerpDelta(double4 a, double4 b, double dr, double dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. diff --git a/include/math/vector/float.hpp b/include/math/vector/float.hpp index eb01eda..de69991 100644 --- a/include/math/vector/float.hpp +++ b/include/math/vector/float.hpp @@ -774,20 +774,17 @@ static float2 repeat(float2 v) noexcept { return float2(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float2 lerp(float2 a, float2 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float2 lerp(float2 a, float2 b, float t) noexcept { return fma(float2(t), b, fma(float2(-t), a, a)); } /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static float2 lerpDelta(float2 a, float2 b, float f, float dt) noexcept -{ - return a + (1.0f - std::pow(f, dt)) * (b - a); -} +static float2 lerpDelta(float2 a, float2 b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. @@ -1079,20 +1076,17 @@ static float3 repeat(float3 v) noexcept { return float3(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float3 lerp(float3 a, float3 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float3 lerp(float3 a, float3 b, float t) noexcept { return fma(float3(t), b, fma(float3(-t), a, a)); } /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static float3 lerpDelta(float3 a, float3 b, float f, float dt) noexcept -{ - return a + (1.0f - std::pow(f, dt)) * (b - a); -} +static float3 lerpDelta(float3 a, float3 b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. @@ -1393,20 +1387,17 @@ static float4 repeat(float4 v) noexcept { return float4(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float4 lerp(float4 a, float4 b, float t) noexcept { return a * (1.0f - t) + b * t; } +static constexpr float4 lerp(float4 a, float4 b, float t) noexcept { return fma(float4(t), b, fma(float4(-t), a, a)); } /** - * @brief Linearly interpolates each component of the vector between a and b using t, taking into account delta time. + * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! * * @param a minimum vector (t == 0.0) * @param b maximum vector (t == 1.0) - * @param t target interpolation value (0.0 - 1.0) + * @param dr target decay rate value * @param dt current delta time */ -static float4 lerpDelta(float4 a, float4 b, float f, float dt) noexcept -{ - return a + (1.0f - std::pow(f, dt)) * (b - a); -} +static float4 lerpDelta(float4 a, float4 b, float dr, float dt) noexcept { return lerp(b, a, std::exp(-dr * dt)); } /** * @brief Computes the power of each component of base b raised to the corresponding exponent e. diff --git a/include/math/vector/half.hpp b/include/math/vector/half.hpp index 1989469..bcd4461 100644 --- a/include/math/vector/half.hpp +++ b/include/math/vector/half.hpp @@ -100,6 +100,12 @@ struct [[nodiscard]] half2 constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + constexpr bool operator==(half2 v) const noexcept { return x == v.x && y == v.y; } + constexpr bool operator!=(half2 v) const noexcept { return x != v.x || y != v.y; } + + constexpr bool operator==(float n) const noexcept { return *this == half2(n); } + constexpr bool operator!=(float n) const noexcept { return *this != half2(n); } + static const half2 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan, left, right, bottom, top; }; @@ -212,6 +218,12 @@ struct [[nodiscard]] half3 constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + constexpr bool operator==(half3 v) const noexcept { return x == v.x && y == v.y && z == v.z; } + constexpr bool operator!=(half3 v) const noexcept { return x != v.x || y != v.y || z != v.z; } + + constexpr bool operator==(half n) const noexcept { return *this == half3(n); } + constexpr bool operator!=(half n) const noexcept { return *this != half3(n); } + static const half3 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan, left, right, bottom, top, back, front; }; @@ -360,6 +372,12 @@ struct [[nodiscard]] half4 constexpr explicit operator sbyte2() const noexcept { return sbyte2((int8)x, (int8)y); } constexpr explicit operator byte2() const noexcept { return byte2((uint8)x, (uint8)y); } + constexpr bool operator==(half4 v) const noexcept { return x == v.x && y == v.y && z == v.z && w == v.w; } + constexpr bool operator!=(half4 v) const noexcept { return x != v.x || y != v.y || z != v.z || w != v.w; } + + constexpr bool operator==(half n) const noexcept { return *this == half4(n); } + constexpr bool operator!=(half n) const noexcept { return *this != half4(n); } + static const half4 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan; }; diff --git a/include/math/vector/int.hpp b/include/math/vector/int.hpp index 1518d4b..9dce557 100644 --- a/include/math/vector/int.hpp +++ b/include/math/vector/int.hpp @@ -46,10 +46,20 @@ struct [[nodiscard]] int2 */ constexpr int2(int32 x, int32 y) noexcept : x(x), y(y) { } + constexpr int2(uint4 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(uint3 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } constexpr int2(uint2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(short4 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(short3 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } constexpr int2(short2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(ushort4 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(ushort3 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } constexpr int2(ushort2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(sbyte4 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(sbyte3 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } constexpr int2(sbyte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(byte4 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } + constexpr int2(byte3 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } constexpr int2(byte2 xy) noexcept : x((int32)xy.x), y((int32)xy.y) { } /******************************************************************************************************************* @@ -198,10 +208,15 @@ struct [[nodiscard]] int3 */ constexpr int3(int32 x, int2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr int3(uint4 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } constexpr int3(uint3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + constexpr int3(short4 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } constexpr int3(short3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + constexpr int3(ushort4 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } constexpr int3(ushort3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + constexpr int3(sbyte4 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } constexpr int3(sbyte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } + constexpr int3(byte4 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } constexpr int3(byte3 xyz) noexcept : x((int32)xyz.x), y((int32)xyz.y), z((int32)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/long.hpp b/include/math/vector/long.hpp index f50b781..8cc20ad 100644 --- a/include/math/vector/long.hpp +++ b/include/math/vector/long.hpp @@ -46,12 +46,26 @@ struct [[nodiscard]] long2 */ constexpr long2(int64 x, int64 y) noexcept : x(x), y(y) { } + constexpr long2(ulong4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(ulong3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(ulong2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(int4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(int3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(int2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(uint4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(uint3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(uint2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(short4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(short3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(short2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(ushort4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(ushort3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(ushort2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(sbyte4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(sbyte3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(sbyte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(byte4 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } + constexpr long2(byte3 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } constexpr long2(byte2 xy) noexcept : x((int64)xy.x), y((int64)xy.y) { } /******************************************************************************************************************* @@ -202,12 +216,19 @@ struct [[nodiscard]] long3 */ constexpr long3(int64 x, long2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr long3(ulong4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(ulong3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(int4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(int3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(uint4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(uint3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(short4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(short3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(ushort4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(ushort3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(sbyte4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(sbyte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } + constexpr long3(byte4 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } constexpr long3(byte3 xyz) noexcept : x((int64)xyz.x), y((int64)xyz.y), z((int64)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/sbyte.hpp b/include/math/vector/sbyte.hpp index 7416432..3e10fb1 100644 --- a/include/math/vector/sbyte.hpp +++ b/include/math/vector/sbyte.hpp @@ -46,6 +46,8 @@ struct [[nodiscard]] sbyte2 */ constexpr sbyte2(int8 x, int8 y) noexcept : x(x), y(y) { } + constexpr sbyte2(byte4 xy) noexcept : x((int8)xy.x), y((int8)xy.y) { } + constexpr sbyte2(byte3 xy) noexcept : x((int8)xy.x), y((int8)xy.y) { } constexpr sbyte2(byte2 xy) noexcept : x((int8)xy.x), y((int8)xy.y) { } /******************************************************************************************************************* @@ -190,6 +192,7 @@ struct [[nodiscard]] sbyte3 */ constexpr sbyte3(int8 x, sbyte2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr sbyte3(byte4 xyz) noexcept : x((int8)xyz.x), y((int8)xyz.y), z((int8)xyz.z) { } constexpr sbyte3(byte3 xyz) noexcept : x((int8)xyz.x), y((int8)xyz.y), z((int8)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/short.hpp b/include/math/vector/short.hpp index 54e5f76..c098dfb 100644 --- a/include/math/vector/short.hpp +++ b/include/math/vector/short.hpp @@ -46,8 +46,14 @@ struct [[nodiscard]] short2 */ constexpr short2(int16 x, int16 y) noexcept : x(x), y(y) { } + constexpr short2(ushort4 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + constexpr short2(ushort3 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } constexpr short2(ushort2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + constexpr short2(sbyte4 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + constexpr short2(sbyte3 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } constexpr short2(sbyte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + constexpr short2(byte4 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } + constexpr short2(byte3 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } constexpr short2(byte2 xy) noexcept : x((int16)xy.x), y((int16)xy.y) { } /******************************************************************************************************************* @@ -194,8 +200,11 @@ struct [[nodiscard]] short3 */ constexpr short3(int16 x, short2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr short3(ushort4 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } constexpr short3(ushort3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } + constexpr short3(sbyte4 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } constexpr short3(sbyte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } + constexpr short3(byte4 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } constexpr short3(byte3 xyz) noexcept : x((int16)xyz.x), y((int16)xyz.y), z((int16)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/uint.hpp b/include/math/vector/uint.hpp index 4be9a56..0f1afb7 100644 --- a/include/math/vector/uint.hpp +++ b/include/math/vector/uint.hpp @@ -49,9 +49,17 @@ struct [[nodiscard]] uint2 */ constexpr uint2(uint32 x, uint32 y) noexcept : x(x), y(y) { } + constexpr uint2(short4 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(short3 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } constexpr uint2(short2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(ushort4 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(ushort3 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } constexpr uint2(ushort2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(sbyte4 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(sbyte3 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } constexpr uint2(sbyte2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(byte4 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } + constexpr uint2(byte3 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } constexpr uint2(byte2 xy) noexcept : x((uint32)xy.x), y((uint32)xy.y) { } /** @@ -193,9 +201,13 @@ struct [[nodiscard]] uint3 */ constexpr uint3(uint32 x, uint2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr uint3(short4 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } constexpr uint3(short3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(ushort4 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } constexpr uint3(ushort3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(sbyte4 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } constexpr uint3(sbyte3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } + constexpr uint3(byte4 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } constexpr uint3(byte3 xyz) noexcept : x((uint32)xyz.x), y((uint32)xyz.y), z((uint32)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/ulong.hpp b/include/math/vector/ulong.hpp index 671a454..dd60d7b 100644 --- a/include/math/vector/ulong.hpp +++ b/include/math/vector/ulong.hpp @@ -48,11 +48,23 @@ struct [[nodiscard]] ulong2 */ constexpr ulong2(uint64 x, uint64 y) noexcept : x(x), y(y) { } + constexpr ulong2(int4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(int3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(int2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(uint4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(uint3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(uint2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(short4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(short3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(short2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(ushort4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(ushort3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(ushort2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(sbyte4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(sbyte3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(sbyte2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(byte4 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } + constexpr ulong2(byte3 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } constexpr ulong2(byte2 xy) noexcept : x((uint64)xy.x), y((uint64)xy.y) { } /** @@ -195,11 +207,17 @@ struct [[nodiscard]] ulong3 */ constexpr ulong3(uint64 x, ulong2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr ulong3(int4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(int3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(uint4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(uint3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(short4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(short3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(ushort4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(ushort3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(sbyte4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(sbyte3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } + constexpr ulong3(byte4 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } constexpr ulong3(byte3 xyz) noexcept : x((uint64)xyz.x), y((uint64)xyz.y), z((uint64)xyz.z) { } /******************************************************************************************************************* diff --git a/include/math/vector/ushort.hpp b/include/math/vector/ushort.hpp index f03fe02..fe88538 100644 --- a/include/math/vector/ushort.hpp +++ b/include/math/vector/ushort.hpp @@ -48,7 +48,11 @@ struct [[nodiscard]] ushort2 */ constexpr ushort2(uint16 x, uint16 y) noexcept : x(x), y(y) { } + constexpr ushort2(sbyte4 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } + constexpr ushort2(sbyte3 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } constexpr ushort2(sbyte2 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } + constexpr ushort2(byte4 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } + constexpr ushort2(byte3 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } constexpr ushort2(byte2 xy) noexcept : x((uint16)xy.x), y((uint16)xy.y) { } /** @@ -188,7 +192,9 @@ struct [[nodiscard]] ushort3 */ constexpr ushort3(uint16 x, ushort2 yz) noexcept : x(x), y(yz.x), z(yz.y) { } + constexpr ushort3(sbyte4 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } constexpr ushort3(sbyte3 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } + constexpr ushort3(byte4 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } constexpr ushort3(byte3 xyz) noexcept : x((uint16)xyz.x), y((uint16)xyz.y), z((uint16)xyz.z) { } /******************************************************************************************************************* From 9b756b1ba3fede7f2b9fbcd934ac5706ba7fe5e7 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 20:21:42 +0300 Subject: [PATCH 04/14] Fix building --- include/math/common.hpp | 4 ++-- include/math/simd/vector/half.hpp | 4 ++-- include/math/vector/double.hpp | 15 +++------------ include/math/vector/float.hpp | 6 +++--- include/math/vector/half.hpp | 4 ++-- 5 files changed, 12 insertions(+), 21 deletions(-) diff --git a/include/math/common.hpp b/include/math/common.hpp index 0a38f41..a2123f2 100644 --- a/include/math/common.hpp +++ b/include/math/common.hpp @@ -104,7 +104,7 @@ static double repeat(double v) noexcept * @param b maximum value (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float lerp(float a, float b, float t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } +static float lerp(float a, float b, float t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } /** * @brief Linearly interpolates between a and b values using t. * @@ -112,7 +112,7 @@ static constexpr float lerp(float a, float b, float t) noexcept { return std::fm * @param b maximum value (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double lerp(double a, double b, double t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } +static double lerp(double a, double b, double t) noexcept { return std::fma(t, b, std::fma(-t, a, a)); } /** * @brief Linearly interpolates between a and b values taking into account delta time. diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index cd826f2..0740189 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -130,7 +130,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(u32x4 v) noexcept { - #if defined(MATH_SIMD_SUPPORT_SSE) + #if defined(MATH_SIMD_SUPPORT_AVX2) data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvt_f32_f16(vcvtq_f32_u32(v.data)); @@ -140,7 +140,7 @@ struct [[nodiscard]] f16x4 } explicit f16x4(i32x4 v) noexcept { - #if defined(MATH_SIMD_SUPPORT_SSE) + #if defined(MATH_SIMD_SUPPORT_AVX2) data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvt_f32_f16(vcvtq_f32_s32(v.data)); diff --git a/include/math/vector/double.hpp b/include/math/vector/double.hpp index 05af3ff..b9dc47a 100644 --- a/include/math/vector/double.hpp +++ b/include/math/vector/double.hpp @@ -785,10 +785,7 @@ static double2 repeat(double2 v) noexcept { return double2(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double2 lerp(double2 a, double2 b, double t) noexcept -{ - return fma(double2(t), b, fma(double2(-t), a, a)); -} +static double2 lerp(double2 a, double2 b, double t) noexcept { return fma(double2(t), b, fma(double2(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1090,10 +1087,7 @@ static double3 repeat(double3 v) noexcept { return double3(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double3 lerp(double3 a, double3 b, double t) noexcept -{ - return fma(double3(t), b, fma(double3(-t), a, a)); -} +static double3 lerp(double3 a, double3 b, double t) noexcept { return fma(double3(t), b, fma(double3(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1404,10 +1398,7 @@ static double4 repeat(double4 v) noexcept { return double4(repeat(v.x), repeat(v * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr double4 lerp(double4 a, double4 b, double t) noexcept -{ - return fma(double4(t), b, fma(double4(-t), a, a)); -} +static double4 lerp(double4 a, double4 b, double t) noexcept { return fma(double4(t), b, fma(double4(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! diff --git a/include/math/vector/float.hpp b/include/math/vector/float.hpp index de69991..99643d2 100644 --- a/include/math/vector/float.hpp +++ b/include/math/vector/float.hpp @@ -774,7 +774,7 @@ static float2 repeat(float2 v) noexcept { return float2(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float2 lerp(float2 a, float2 b, float t) noexcept { return fma(float2(t), b, fma(float2(-t), a, a)); } +static float2 lerp(float2 a, float2 b, float t) noexcept { return fma(float2(t), b, fma(float2(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1076,7 +1076,7 @@ static float3 repeat(float3 v) noexcept { return float3(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float3 lerp(float3 a, float3 b, float t) noexcept { return fma(float3(t), b, fma(float3(-t), a, a)); } +static float3 lerp(float3 a, float3 b, float t) noexcept { return fma(float3(t), b, fma(float3(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! @@ -1387,7 +1387,7 @@ static float4 repeat(float4 v) noexcept { return float4(repeat(v.x), repeat(v.y) * @param b maximum vector (t == 1.0) * @param t target interpolation value (0.0 - 1.0) */ -static constexpr float4 lerp(float4 a, float4 b, float t) noexcept { return fma(float4(t), b, fma(float4(-t), a, a)); } +static float4 lerp(float4 a, float4 b, float t) noexcept { return fma(float4(t), b, fma(float4(-t), a, a)); } /** * @brief Linearly interpolates each component of the vector between a and b taking into account delta time. * @note Always use this function instead of basic lerp() when you have variable delta time! diff --git a/include/math/vector/half.hpp b/include/math/vector/half.hpp index bcd4461..6d7452b 100644 --- a/include/math/vector/half.hpp +++ b/include/math/vector/half.hpp @@ -103,8 +103,8 @@ struct [[nodiscard]] half2 constexpr bool operator==(half2 v) const noexcept { return x == v.x && y == v.y; } constexpr bool operator!=(half2 v) const noexcept { return x != v.x || y != v.y; } - constexpr bool operator==(float n) const noexcept { return *this == half2(n); } - constexpr bool operator!=(float n) const noexcept { return *this != half2(n); } + constexpr bool operator==(half n) const noexcept { return *this == half2(n); } + constexpr bool operator!=(half n) const noexcept { return *this != half2(n); } static const half2 zero, one, minusOne, min, minusMin, max, minusMax, epsilon, inf, minusInf, nan, left, right, bottom, top; From 0f442f2df5193e1d01bd3f585d9a99dfc3553fc5 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 20:25:57 +0300 Subject: [PATCH 05/14] Fix macOS build --- include/math/simd/vector/half.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index 0740189..ff88ff9 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -133,7 +133,7 @@ struct [[nodiscard]] f16x4 #if defined(MATH_SIMD_SUPPORT_AVX2) data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) - data = vcvt_f32_f16(vcvtq_f32_u32(v.data)); + data = vcvt_f16_f32(vcvtq_f32_u32(v.data)); #else halfs = (half4)v.uints; #endif @@ -143,7 +143,7 @@ struct [[nodiscard]] f16x4 #if defined(MATH_SIMD_SUPPORT_AVX2) data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) - data = vcvt_f32_f16(vcvtq_f32_s32(v.data)); + data = vcvt_f16_f32(vcvtq_f32_s32(v.data)); #else halfs = (half4)v.ints; #endif From 60ef79bc5c0b73fc154af188e0d63015dbabe550 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 20:28:43 +0300 Subject: [PATCH 06/14] Fix macOS build --- include/math/simd/vector/float.hpp | 2 +- include/math/simd/vector/half.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/math/simd/vector/float.hpp b/include/math/simd/vector/float.hpp index 9a5bfc6..08c2ceb 100644 --- a/include/math/simd/vector/float.hpp +++ b/include/math/simd/vector/float.hpp @@ -412,7 +412,7 @@ struct [[nodiscard]] f32x4 #if defined(MATH_SIMD_SUPPORT_AVX2) return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT); #elif defined(MATH_SIMD_SUPPORT_NEON) - return vcvt_f16_f32(v.data); + return vcvt_f16_f32(data); #else return f16x4((half4)floats); #endif diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index ff88ff9..d12ef9f 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -297,7 +297,7 @@ struct [[nodiscard]] f16x4 #if defined(MATH_SIMD_SUPPORT_SSE) return _mm_movemask_epi8(_mm_cmpeq_epi32(data, v.data)) == 0xFFFF; #elif defined(MATH_SIMD_SUPPORT_NEON) - return vminv_u16(vceq_f16(data, v.data)) == 0xFFFFFFFFu; + return vminv_u16(vceq_f16(data, v.data)) == 0xFFFFu; #else return halfs == v.halfs; #endif From e1c61ee12f2cd8d6e6fb5601808d902e3fbfc36d Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 21:41:56 +0300 Subject: [PATCH 07/14] Fix half float support MSVC --- include/math/color-space.hpp | 2 +- include/math/simd/vector/float.hpp | 2 +- include/math/simd/vector/half.hpp | 14 ++-- include/math/types.hpp | 114 +++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 15 deletions(-) diff --git a/include/math/color-space.hpp b/include/math/color-space.hpp index 07324f0..56bdf1a 100644 --- a/include/math/color-space.hpp +++ b/include/math/color-space.hpp @@ -256,7 +256,7 @@ static uint32 encodeB10G11R11(float value, uint32 bits, uint32 mask) noexcept */ static uint32 encodeB10G11R11(f32x4 rgb) noexcept { - rgb = clamp(rgb, f32x4::zero, f32x4(FLOAT_BIG_16)); + rgb = clamp(rgb, f32x4::zero, f32x4(FLT16_MAX)); auto r = encodeB10G11R11(rgb.getX(), 6, 0b111111); auto g = encodeB10G11R11(rgb.getY(), 6, 0b111111); auto b = encodeB10G11R11(rgb.getZ(), 5, 0b11111); diff --git a/include/math/simd/vector/float.hpp b/include/math/simd/vector/float.hpp index 08c2ceb..d99d3f5 100644 --- a/include/math/simd/vector/float.hpp +++ b/include/math/simd/vector/float.hpp @@ -410,7 +410,7 @@ struct [[nodiscard]] f32x4 explicit operator f16x4() const noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT); + return _mm_cvtps_ph(data, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) return vcvt_f16_f32(data); #else diff --git a/include/math/simd/vector/half.hpp b/include/math/simd/vector/half.hpp index d12ef9f..bece1e0 100644 --- a/include/math/simd/vector/half.hpp +++ b/include/math/simd/vector/half.hpp @@ -62,7 +62,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(half xyzw) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_set1_ps(xyzw), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_set1_ps(xyzw), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vdup_n_f16(xyzw); #else @@ -80,7 +80,7 @@ struct [[nodiscard]] f16x4 f16x4(half x, half y, half z, half w) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_set_ps(w, z, y, x), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_set_ps(w, z, y, x), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ x, y, z, w }; #else @@ -98,7 +98,7 @@ struct [[nodiscard]] f16x4 f16x4(half x, half y, half z) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_set_ps(z, z, y, x), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_set_ps(z, z, y, x), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ x, y, z, z }; #else @@ -131,7 +131,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(u32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvt_f16_f32(vcvtq_f32_u32(v.data)); #else @@ -141,7 +141,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(i32x4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_cvtepi32_ps(v.data), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = vcvt_f16_f32(vcvtq_f32_s32(v.data)); #else @@ -156,7 +156,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(half4 v) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_set_ps(v.w, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_set_ps(v.w, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ v.x, v.y, v.z, v.w }; #else @@ -171,7 +171,7 @@ struct [[nodiscard]] f16x4 explicit f16x4(half3 v) noexcept { #if defined(MATH_SIMD_SUPPORT_AVX2) - data = _mm_cvtps_ph(_mm_set_ps(v.z, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT); + data = _mm_cvtps_ph(_mm_set_ps(v.z, v.z, v.y, v.x), _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); #elif defined(MATH_SIMD_SUPPORT_NEON) data = (float16x4_t){ v.x, v.y, v.z, v.z }; #else diff --git a/include/math/types.hpp b/include/math/types.hpp index f0c2881..0537b37 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -24,16 +24,12 @@ #include #include -#ifndef FLT16_MIN -#define _Float16 uint16_t // Note: MSVC fix +#if defined(__AVX2__) +#include #endif -#define FLOAT_SMALL_16 0.00006103515625f /**< Maximum representable finite positive 16-bit value. */ -#define FLOAT_BIG_16 65504.0f /**< Smallest positive normalized 16-bit value. */ - namespace math { - /** * @brief A signed 8-bit integer type. (-128 to 127) */ @@ -73,10 +69,116 @@ typedef uint64_t uint64; */ typedef size_t psize; +//********************************************************************************************************************** +#ifndef FLT16_MIN // Note: MSVC half float support. + +#define FLT16_MIN 0.00006103515625f /**< Minimum positive value representable as a 16-bit float. */ +#define FLT16_MAX 65504.0f /**< Maximum representable finite positive 16-bit value. */ +#define FLT16_EPSILON 0.0009765625f /**< Smallest positive 16-bit value. */ + +#define FLT16_MANT_DIG 11 +#define FLT16_DECIMAL_DIG 5 +#define FLT16_DIG 3 +#define FLT16_MIN_EXP -13 +#define FLT16_MIN_10_EXP -4 +#define FLT16_MAX_EXP 16 +#define FLT16_MAX_10_EXP 4 +#define FLT16_RADIX 2 + +/** + * @brief An IEEE-754 half-precision 16-bit floating-point number. + */ +struct half +{ + uint16_t data = 0; + + static uint16_t floatToHalf(float f) noexcept + { + auto i = *(const int*)&f; + auto s = (i >> 16) & 0x00008000; + auto e = ((i >> 23) & 0x000000ff) - (127 - 15); + auto m = i & 0x007fffff; + + if (e <= 0) + { + if (e < -10) return s; + m = m | 0x00800000; + auto t = 14 - e; + auto a = (1 << (t - 1)) - 1; + auto b = (m >> t) & 1; + m = (m + a + b) >> t; + return s | m; + } + else if (e == 0xff - (127 - 15)) + { + if (m == 0) return s | 0x7c00; + else + { + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } + else + { + m = m + 0x00000fff + ((m >> 13) & 1); + if (m & 0x00800000) { m = 0; e += 1; } + if (e > 30) + { + volatile float f = 1e10f; + for (int i = 0; i < 10; i++) f *= f; + return s | 0x7c00; + } + return s | (e << 10) | (m >> 13); + } + } + static int halfToFloat(int h) noexcept + { + auto s = (h >> 15) & 0x00000001; + auto e = (h >> 10) & 0x0000001f; + auto m = h & 0x000003ff; + + if (e == 0) + { + if (m == 0) return s << 31; + else + { + while (!(m & 0x00000400)) { m <<= 1; e -= 1; } + e += 1; m &= ~0x00000400; + } + } + else if (e == 31) + { + if (m == 0) return (s << 31) | 0x7f800000; + else return (s << 31) | 0x7f800000 | (m << 13); + } + + e = e + (127 - 15); m = m << 13; + return (s << 31) | (e << 23) | m; + } + Half(float f) noexcept + { + #if defined(__AVX2__) + data = _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + #else + data = floatToHalf(f); + #endif + } + operator float() const noexcept + { + #if defined(__AVX2__) + return _cvtsh_ss(data); + #else + auto i = halfToFloat(data); + return *(const float)&i; + #endif + } +}; +#else /** * @brief An IEEE-754 half-precision 16-bit floating-point number. */ typedef _Float16 half; +#endif /** * @brief Half-precision 16-bit floating-point number literal. From 9b03d97a39db3b59af86697001be6fc7a7fb2b82 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 21:44:08 +0300 Subject: [PATCH 08/14] Fix build --- include/math/types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/math/types.hpp b/include/math/types.hpp index 0537b37..ada40bb 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -155,7 +155,7 @@ struct half e = e + (127 - 15); m = m << 13; return (s << 31) | (e << 23) | m; } - Half(float f) noexcept + half(float f) noexcept { #if defined(__AVX2__) data = _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); From 199d3bd43e9b860da8d502f84c4d78aa1bff385a Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 21:59:15 +0300 Subject: [PATCH 09/14] Fix MSVC build --- CMakeLists.txt | 6 ++- include/math/types.hpp | 91 +----------------------------------------- 2 files changed, 7 insertions(+), 90 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb4a9a5..35435bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,11 @@ project(math VERSION 0.2.0 LANGUAGES CXX DESCRIPTION "Linear algebra mathematics library." HOMEPAGE_URL "https://github.com/cfnptr/math") -set(CMAKE_CXX_STANDARD 17) +if(NOT MSVC) + set(CMAKE_CXX_STANDARD 17) +else() + set(CMAKE_CXX_STANDARD 23) # Because MSVC does not support half floats... +endif() set(CMAKE_CXX_STANDARD_REQUIRED TRUE) option(MATH_BUILD_SHARED "Build Math shared library" ON) diff --git a/include/math/types.hpp b/include/math/types.hpp index ada40bb..cbc96ec 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -23,10 +23,7 @@ #include #include #include - -#if defined(__AVX2__) -#include -#endif +#include namespace math { @@ -88,91 +85,7 @@ typedef size_t psize; /** * @brief An IEEE-754 half-precision 16-bit floating-point number. */ -struct half -{ - uint16_t data = 0; - - static uint16_t floatToHalf(float f) noexcept - { - auto i = *(const int*)&f; - auto s = (i >> 16) & 0x00008000; - auto e = ((i >> 23) & 0x000000ff) - (127 - 15); - auto m = i & 0x007fffff; - - if (e <= 0) - { - if (e < -10) return s; - m = m | 0x00800000; - auto t = 14 - e; - auto a = (1 << (t - 1)) - 1; - auto b = (m >> t) & 1; - m = (m + a + b) >> t; - return s | m; - } - else if (e == 0xff - (127 - 15)) - { - if (m == 0) return s | 0x7c00; - else - { - m >>= 13; - return s | 0x7c00 | m | (m == 0); - } - } - else - { - m = m + 0x00000fff + ((m >> 13) & 1); - if (m & 0x00800000) { m = 0; e += 1; } - if (e > 30) - { - volatile float f = 1e10f; - for (int i = 0; i < 10; i++) f *= f; - return s | 0x7c00; - } - return s | (e << 10) | (m >> 13); - } - } - static int halfToFloat(int h) noexcept - { - auto s = (h >> 15) & 0x00000001; - auto e = (h >> 10) & 0x0000001f; - auto m = h & 0x000003ff; - - if (e == 0) - { - if (m == 0) return s << 31; - else - { - while (!(m & 0x00000400)) { m <<= 1; e -= 1; } - e += 1; m &= ~0x00000400; - } - } - else if (e == 31) - { - if (m == 0) return (s << 31) | 0x7f800000; - else return (s << 31) | 0x7f800000 | (m << 13); - } - - e = e + (127 - 15); m = m << 13; - return (s << 31) | (e << 23) | m; - } - half(float f) noexcept - { - #if defined(__AVX2__) - data = _cvtss_sh(f, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); - #else - data = floatToHalf(f); - #endif - } - operator float() const noexcept - { - #if defined(__AVX2__) - return _cvtsh_ss(data); - #else - auto i = halfToFloat(data); - return *(const float)&i; - #endif - } -}; +typedef std::float16_t half; #else /** * @brief An IEEE-754 half-precision 16-bit floating-point number. From bac4825cce53496ec9f3c4482faf5b53746635a6 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 22:00:59 +0300 Subject: [PATCH 10/14] MSVC --- include/math/types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/math/types.hpp b/include/math/types.hpp index cbc96ec..bce924d 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -23,7 +23,6 @@ #include #include #include -#include namespace math { @@ -68,6 +67,7 @@ typedef size_t psize; //********************************************************************************************************************** #ifndef FLT16_MIN // Note: MSVC half float support. +#include #define FLT16_MIN 0.00006103515625f /**< Minimum positive value representable as a 16-bit float. */ #define FLT16_MAX 65504.0f /**< Maximum representable finite positive 16-bit value. */ From 9f671c52f2162e406a4443b04595b56413d4267d Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 22:20:36 +0300 Subject: [PATCH 11/14] Drop MSVC --- .github/workflows/cmake.yml | 7 +++++++ CMakeLists.txt | 8 +------- include/math/types.hpp | 24 ------------------------ 3 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b21b020..c33df47 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -21,10 +21,17 @@ jobs: run: cmake -E make_directory ${{runner.workspace}}/build - name: Configure CMake + if: matrix.os != 'windows-latest' shell: bash working-directory: ${{runner.workspace}}/build run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + - name: Configure Windows CMake + if: matrix.os == 'windows-latest' + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -T ClangCL -A x64 + - name: Build project working-directory: ${{runner.workspace}}/build shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 35435bb..e7b5f63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,11 +26,7 @@ project(math VERSION 0.2.0 LANGUAGES CXX DESCRIPTION "Linear algebra mathematics library." HOMEPAGE_URL "https://github.com/cfnptr/math") -if(NOT MSVC) - set(CMAKE_CXX_STANDARD 17) -else() - set(CMAKE_CXX_STANDARD 23) # Because MSVC does not support half floats... -endif() +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) option(MATH_BUILD_SHARED "Build Math shared library" ON) @@ -40,14 +36,12 @@ set(MATH_SOURCES source/aabb.cpp source/bvh.cpp) add_library(math-static STATIC ${MATH_SOURCES}) target_include_directories(math-static PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_compile_definitions(math-static PUBLIC _USE_MATH_DEFINES NOMINMAX) if(MATH_BUILD_SHARED) add_library(math-shared SHARED ${MATH_SOURCES}) set_target_properties(math-shared PROPERTIES OUTPUT_NAME "math" WINDOWS_EXPORT_ALL_SYMBOLS ON) target_include_directories(math-shared PUBLIC ${PROJECT_SOURCE_DIR}/include) - target_compile_definitions(math-shared PUBLIC _USE_MATH_DEFINES NOMINMAX) endif() if(MATH_BUILD_TESTS) diff --git a/include/math/types.hpp b/include/math/types.hpp index bce924d..5145a20 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -65,34 +65,10 @@ typedef uint64_t uint64; */ typedef size_t psize; -//********************************************************************************************************************** -#ifndef FLT16_MIN // Note: MSVC half float support. -#include - -#define FLT16_MIN 0.00006103515625f /**< Minimum positive value representable as a 16-bit float. */ -#define FLT16_MAX 65504.0f /**< Maximum representable finite positive 16-bit value. */ -#define FLT16_EPSILON 0.0009765625f /**< Smallest positive 16-bit value. */ - -#define FLT16_MANT_DIG 11 -#define FLT16_DECIMAL_DIG 5 -#define FLT16_DIG 3 -#define FLT16_MIN_EXP -13 -#define FLT16_MIN_10_EXP -4 -#define FLT16_MAX_EXP 16 -#define FLT16_MAX_10_EXP 4 -#define FLT16_RADIX 2 - -/** - * @brief An IEEE-754 half-precision 16-bit floating-point number. - */ -typedef std::float16_t half; -#else /** * @brief An IEEE-754 half-precision 16-bit floating-point number. */ typedef _Float16 half; -#endif - /** * @brief Half-precision 16-bit floating-point number literal. */ From 949445d42529458faf06c17e44e6510ea3e6bc76 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 22:27:53 +0300 Subject: [PATCH 12/14] Try ti fix windows --- CMakeLists.txt | 2 ++ include/math/types.hpp | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7b5f63..3c5cce6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,12 +36,14 @@ set(MATH_SOURCES source/aabb.cpp source/bvh.cpp) add_library(math-static STATIC ${MATH_SOURCES}) target_include_directories(math-static PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_compile_definitions(math-static PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__) if(MATH_BUILD_SHARED) add_library(math-shared SHARED ${MATH_SOURCES}) set_target_properties(math-shared PROPERTIES OUTPUT_NAME "math" WINDOWS_EXPORT_ALL_SYMBOLS ON) target_include_directories(math-shared PUBLIC ${PROJECT_SOURCE_DIR}/include) + target_compile_definitions(math-shared PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__) endif() if(MATH_BUILD_TESTS) diff --git a/include/math/types.hpp b/include/math/types.hpp index 5145a20..d705b2a 100644 --- a/include/math/types.hpp +++ b/include/math/types.hpp @@ -18,8 +18,6 @@ */ #pragma once - -#define __STDC_WANT_IEC_60559_TYPES_EXT__ #include #include #include From 0a984fd2f26bb2d83fe6f2ec48631029e0165856 Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 22:33:09 +0300 Subject: [PATCH 13/14] win fix --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c5cce6..42710ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,13 +37,18 @@ set(MATH_SOURCES source/aabb.cpp source/bvh.cpp) add_library(math-static STATIC ${MATH_SOURCES}) target_include_directories(math-static PUBLIC ${PROJECT_SOURCE_DIR}/include) target_compile_definitions(math-static PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__) +if(WIN32) + target_compile_definitions(math-static PUBLIC _USE_MATH_DEFINES NOMINMAX) +endif() if(MATH_BUILD_SHARED) add_library(math-shared SHARED ${MATH_SOURCES}) set_target_properties(math-shared PROPERTIES OUTPUT_NAME "math" WINDOWS_EXPORT_ALL_SYMBOLS ON) target_include_directories(math-shared PUBLIC ${PROJECT_SOURCE_DIR}/include) - target_compile_definitions(math-shared PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__) + if(WIN32) + target_compile_definitions(math-shared PUBLIC _USE_MATH_DEFINES NOMINMAX) + endif() endif() if(MATH_BUILD_TESTS) From e9ccc9c0ab6f5a82b08382e186aa16d1ee4be26e Mon Sep 17 00:00:00 2001 From: Nikita Fediuchin Date: Mon, 20 Jul 2026 22:33:58 +0300 Subject: [PATCH 14/14] fix --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42710ea..44fd52b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ if(MATH_BUILD_SHARED) set_target_properties(math-shared PROPERTIES OUTPUT_NAME "math" WINDOWS_EXPORT_ALL_SYMBOLS ON) target_include_directories(math-shared PUBLIC ${PROJECT_SOURCE_DIR}/include) + target_compile_definitions(math-shared PUBLIC __STDC_WANT_IEC_60559_TYPES_EXT__) if(WIN32) target_compile_definitions(math-shared PUBLIC _USE_MATH_DEFINES NOMINMAX) endif()