diff --git a/includes/rtm/impl/mask_common.h b/includes/rtm/impl/mask_common.h index e56e6bc8..28e5ab7e 100644 --- a/includes/rtm/impl/mask_common.h +++ b/includes/rtm/impl/mask_common.h @@ -259,6 +259,22 @@ namespace rtm return rtm_impl::mask4_uint64_set{ x, y, z, w }; } + ////////////////////////////////////////////////////////////////////////// + // Creates a mask4 with all 4 components set to true. + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::mask4_bool_set RTM_SIMD_CALL mask_true() RTM_NO_EXCEPT + { + return rtm_impl::mask4_bool_set{ true, true, true, true }; + } + + ////////////////////////////////////////////////////////////////////////// + // Creates a mask4 with all 4 components set to false. + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE constexpr rtm_impl::mask4_bool_set RTM_SIMD_CALL mask_false() RTM_NO_EXCEPT + { + return rtm_impl::mask4_bool_set{ false, false, false, false }; + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/mask4d.h b/includes/rtm/mask4d.h index 1cb09c41..08ebc235 100644 --- a/includes/rtm/mask4d.h +++ b/includes/rtm/mask4d.h @@ -400,6 +400,34 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Per component logical NOT of the input: ~input + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4d RTM_SIMD_CALL mask_not(mask4d_arg0 input) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128i true_mask = _mm_set_epi64x(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL); + __m128d xy = _mm_andnot_pd(input.xy, _mm_castsi128_pd(true_mask)); + __m128d zw = _mm_andnot_pd(input.zw, _mm_castsi128_pd(true_mask)); + return mask4d{ xy, zw }; +#else + const uint64_t* input_ = rtm_impl::bit_cast(&input); + + union + { + mask4d vector; + uint64_t scalar[4]; + } result; + + result.scalar[0] = ~input_[0]; + result.scalar[1] = ~input_[1]; + result.scalar[2] = ~input_[2]; + result.scalar[3] = ~input_[3]; + + return result.vector; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/mask4f.h b/includes/rtm/mask4f.h index 89d9dc0b..72800480 100644 --- a/includes/rtm/mask4f.h +++ b/includes/rtm/mask4f.h @@ -359,6 +359,34 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Per component logical NOT of the input: ~input + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4f RTM_SIMD_CALL mask_not(mask4f_arg0 input) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128i true_mask = _mm_set_epi32(0xFFFFFFFFULL, 0xFFFFFFFFULL, 0xFFFFFFFFULL, 0xFFFFFFFFULL); + return _mm_andnot_ps(input, _mm_castsi128_ps(true_mask)); +#elif defined(RTM_NEON_INTRINSICS) + return vmvnq_u32(input); +#else + const uint32_t* input_ = rtm_impl::bit_cast(&input); + + union + { + mask4f vector; + uint32_t scalar[4]; + } result; + + result.scalar[0] = ~input_[0]; + result.scalar[1] = ~input_[1]; + result.scalar[2] = ~input_[2]; + result.scalar[3] = ~input_[3]; + + return result.vector; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/mask4i.h b/includes/rtm/mask4i.h index a8d5e3f0..e633604e 100644 --- a/includes/rtm/mask4i.h +++ b/includes/rtm/mask4i.h @@ -327,6 +327,21 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Per component logical NOT of the input: ~input + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4i RTM_SIMD_CALL mask_not(mask4i_arg0 input) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128i true_mask = _mm_set_epi32(0xFFFFFFFFULL, 0xFFFFFFFFULL, 0xFFFFFFFFULL, 0xFFFFFFFFULL); + return _mm_andnot_si128(input, true_mask); +#elif defined(RTM_NEON_INTRINSICS) + return RTM_IMPL_MASK4i_SET(vmvnq_u32(RTM_IMPL_MASK4i_GET(input))); +#else + return mask4i{ ~input.x, ~input.y, ~input.z, ~input.w }; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/mask4q.h b/includes/rtm/mask4q.h index 3127f6db..fcbf1026 100644 --- a/includes/rtm/mask4q.h +++ b/includes/rtm/mask4q.h @@ -364,6 +364,34 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Per component logical NOT of the input: ~input + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4q RTM_SIMD_CALL mask_not(mask4q_arg0 input) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128i true_mask = _mm_set_epi64x(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL); + __m128i xy = _mm_andnot_si128(input.xy, true_mask); + __m128i zw = _mm_andnot_si128(input.zw, true_mask); + return mask4q{ xy, zw }; +#else + const uint64_t* input_ = rtm_impl::bit_cast(&input); + + union + { + mask4q vector; + uint64_t scalar[4]; + } result; + + result.scalar[0] = ~input_[0]; + result.scalar[1] = ~input_[1]; + result.scalar[2] = ~input_[2]; + result.scalar[3] = ~input_[3]; + + return result.vector; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/quatd.h b/includes/rtm/quatd.h index a1be7c7a..658ddf2f 100644 --- a/includes/rtm/quatd.h +++ b/includes/rtm/quatd.h @@ -1051,6 +1051,22 @@ namespace rtm return positive_w_angle <= threshold_angle; } + ////////////////////////////////////////////////////////////////////////// + // Per component selection depending on the mask: mask != 0 ? if_true : if_false + // Note that if the mask lanes are not all identical, the resulting quaternion + // may not be normalized. + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE quatd RTM_SIMD_CALL quat_select(mask4d_arg0 mask, quatd_arg1 if_true, quatd_arg2 if_false) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy = RTM_VECTOR2D_SELECT(mask.xy, if_true.xy, if_false.xy); + __m128d zw = RTM_VECTOR2D_SELECT(mask.zw, if_true.zw, if_false.zw); + return quatd{ xy, zw }; +#else + return quatd{ rtm_impl::select(mask.x, if_true.x, if_false.x), rtm_impl::select(mask.y, if_true.y, if_false.y), rtm_impl::select(mask.z, if_true.z, if_false.z), rtm_impl::select(mask.w, if_true.w, if_false.w) }; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/quatf.h b/includes/rtm/quatf.h index 1dcf25a7..3cefc010 100644 --- a/includes/rtm/quatf.h +++ b/includes/rtm/quatf.h @@ -1548,6 +1548,20 @@ namespace rtm return positive_w_angle <= threshold_angle; } + ////////////////////////////////////////////////////////////////////////// + // Per component selection depending on the mask: mask != 0 ? if_true : if_false + // Note that if the mask lanes are not all identical, the resulting quaternion + // may not be normalized. + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE quatf RTM_SIMD_CALL quat_select(mask4f_arg0 mask, quatf_arg1 if_true, quatf_arg2 if_false) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) || defined(RTM_NEON_INTRINSICS) + return RTM_VECTOR4F_SELECT(mask, if_true, if_false); +#else + return quatf{ rtm_impl::select(mask.x, if_true.x, if_false.x), rtm_impl::select(mask.y, if_true.y, if_false.y), rtm_impl::select(mask.z, if_true.z, if_false.z), rtm_impl::select(mask.w, if_true.w, if_false.w) }; +#endif + } + RTM_IMPL_VERSION_NAMESPACE_END } diff --git a/includes/rtm/vector4d.h b/includes/rtm/vector4d.h index 978ba711..920c876c 100644 --- a/includes/rtm/vector4d.h +++ b/includes/rtm/vector4d.h @@ -2088,6 +2088,20 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Returns per component ~0 if not equal, otherwise 0: lhs != rhs ? ~0 : 0 + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4d RTM_SIMD_CALL vector_not_equal(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_lt_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + __m128d zw_lt_pd = _mm_cmpneq_pd(lhs.zw, rhs.zw); + return mask4d{ xy_lt_pd, zw_lt_pd }; +#else + return mask4d{ rtm_impl::get_mask_value(lhs.x != rhs.x), rtm_impl::get_mask_value(lhs.y != rhs.y), rtm_impl::get_mask_value(lhs.z != rhs.z), rtm_impl::get_mask_value(lhs.w != rhs.w) }; +#endif + } + ////////////////////////////////////////////////////////////////////////// // Returns per component ~0 if less than, otherwise 0: lhs < rhs ? ~0 : 0 ////////////////////////////////////////////////////////////////////////// @@ -2554,6 +2568,88 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xyzw] components are not equal, otherwise false: all(lhs.xyzw != rhs.xyzw) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + __m128d zw_eq_pd = _mm_cmpneq_pd(lhs.zw, rhs.zw); + return (_mm_movemask_pd(xy_eq_pd) & _mm_movemask_pd(zw_eq_pd)) == 3; +#else + return lhs.x != rhs.x && lhs.y != rhs.y && lhs.z != rhs.z && lhs.w != rhs.w; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xy] components are not equal, otherwise false: all(lhs.xy != rhs.xy) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal2(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + return _mm_movemask_pd(xy_eq_pd) == 3; +#else + return lhs.x != rhs.x && lhs.y != rhs.y; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xyz] components are not equal, otherwise false: all(lhs.xyz != rhs.xyz) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal3(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + __m128d zw_eq_pd = _mm_cmpneq_pd(lhs.zw, rhs.zw); + return _mm_movemask_pd(xy_eq_pd) == 3 && (_mm_movemask_pd(zw_eq_pd) & 1) != 0; +#else + return lhs.x != rhs.x && lhs.y != rhs.y && lhs.z != rhs.z; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xyzw] components are not equal, otherwise false: any(lhs.xyzw != rhs.xyzw) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + __m128d zw_eq_pd = _mm_cmpneq_pd(lhs.zw, rhs.zw); + return (_mm_movemask_pd(xy_eq_pd) | _mm_movemask_pd(zw_eq_pd)) != 0; +#else + return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xy] components are not equal, otherwise false: any(lhs.xy != rhs.xy) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal2(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + return _mm_movemask_pd(xy_eq_pd) != 0; +#else + return lhs.x != rhs.x || lhs.y != rhs.y; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xyz] components are not equal, otherwise false: any(lhs.xyz != rhs.xyz) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal3(vector4d_arg0 lhs, vector4d_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + __m128d xy_eq_pd = _mm_cmpneq_pd(lhs.xy, rhs.xy); + __m128d zw_eq_pd = _mm_cmpneq_pd(lhs.zw, rhs.zw); + return _mm_movemask_pd(xy_eq_pd) != 0 || (_mm_movemask_pd(zw_eq_pd) & 1) != 0; +#else + return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z; +#endif + } + ////////////////////////////////////////////////////////////////////////// // Returns true if all 4 components are near equal, otherwise false: all(abs(lhs - rhs).xyzw <= threshold) ////////////////////////////////////////////////////////////////////////// diff --git a/includes/rtm/vector4f.h b/includes/rtm/vector4f.h index 7cda1544..30cd787e 100644 --- a/includes/rtm/vector4f.h +++ b/includes/rtm/vector4f.h @@ -2487,6 +2487,20 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Returns per component ~0 if not equal, otherwise 0: lhs != rhs ? ~0 : 0 + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE mask4f RTM_SIMD_CALL vector_not_equal(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + return _mm_cmpneq_ps(lhs, rhs); +#elif defined(RTM_NEON_INTRINSICS) + return vmvnq_u32(vceqq_f32(lhs, rhs)); +#else + return mask4f{ rtm_impl::get_mask_value(lhs.x != rhs.x), rtm_impl::get_mask_value(lhs.y != rhs.y), rtm_impl::get_mask_value(lhs.z != rhs.z), rtm_impl::get_mask_value(lhs.w != rhs.w) }; +#endif + } + ////////////////////////////////////////////////////////////////////////// // Returns per component ~0 if less than, otherwise 0: lhs < rhs ? ~0 : 0 ////////////////////////////////////////////////////////////////////////// @@ -3203,6 +3217,138 @@ namespace rtm #endif } + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xyzw] components are not equal, otherwise false: all(lhs.xyzw != rhs.xyzw) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ALL_TRUE(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x4_t mask = vmvnq_u32(vceqq_f32(lhs, rhs)); + + bool result; + RTM_MASK4F_ALL_TRUE(mask, result); + return result; +#else + return lhs.x != rhs.x && lhs.y != rhs.y && lhs.z != rhs.z && lhs.w != rhs.w; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xy] components are not equal, otherwise false: all(lhs.xy != rhs.xy) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal2(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ALL_TRUE2(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x2_t mask = vmvn_u32(vceq_f32(vget_low_f32(lhs), vget_low_f32(rhs))); + + bool result; + RTM_MASK2F_ALL_TRUE(mask, result); + return result; +#else + return lhs.x != rhs.x && lhs.y != rhs.y; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if all [xyz] components are not equal, otherwise false: all(lhs.xyz != rhs.xyz) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_all_not_equal3(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ALL_TRUE3(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x4_t mask = vmvnq_u32(vceqq_f32(lhs, rhs)); + + bool result; + RTM_MASK4F_ALL_TRUE3(mask, result); + return result; +#else + return lhs.x != rhs.x && lhs.y != rhs.y && lhs.z != rhs.z; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xyzw] components are not equal, otherwise false: any(lhs.xyzw != rhs.xyzw) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ANY_TRUE(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x4_t mask = vmvnq_u32(vceqq_f32(lhs, rhs)); + + bool result; + RTM_MASK4F_ANY_TRUE(mask, result); + return result; +#else + return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xy] components are not equal, otherwise false: any(lhs.xy != rhs.xy) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal2(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ANY_TRUE2(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x2_t mask = vmvn_u32(vceq_f32(vget_low_f32(lhs), vget_low_f32(rhs))); + + bool result; + RTM_MASK2F_ANY_TRUE(mask, result); + return result; +#else + return lhs.x != rhs.x || lhs.y != rhs.y; +#endif + } + + ////////////////////////////////////////////////////////////////////////// + // Returns true if any [xyz] components are not equal, otherwise false: any(lhs.xyz != rhs.xyz) + ////////////////////////////////////////////////////////////////////////// + RTM_DISABLE_SECURITY_COOKIE_CHECK RTM_FORCE_INLINE bool RTM_SIMD_CALL vector_any_not_equal3(vector4f_arg0 lhs, vector4f_arg1 rhs) RTM_NO_EXCEPT + { +#if defined(RTM_SSE2_INTRINSICS) + const __m128 mask = _mm_cmpneq_ps(lhs, rhs); + + bool result; + RTM_MASK4F_ANY_TRUE3(mask, result); + return result; +#elif defined(RTM_NEON_INTRINSICS) + const uint32x4_t mask = vmvnq_u32(vceqq_f32(lhs, rhs)); + + bool result; + RTM_MASK4F_ANY_TRUE3(mask, result); + return result; +#else + return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z; +#endif + } + ////////////////////////////////////////////////////////////////////////// // Returns true if all 4 components are near equal, otherwise false: all(abs(lhs - rhs).xyzw <= threshold) ////////////////////////////////////////////////////////////////////////// diff --git a/tests/sources/test_mask4.cpp b/tests/sources/test_mask4.cpp index a559ca15..3dc4e911 100644 --- a/tests/sources/test_mask4.cpp +++ b/tests/sources/test_mask4.cpp @@ -100,6 +100,26 @@ inline Mask4Type reference_mask_xor(const Mask4Type& input0, const Mask4Type& in return result; } +template +inline Mask4Type reference_mask_not(const Mask4Type& input) +{ + IntType input_[4]; + + static_assert(sizeof(Mask4Type) == sizeof(input_), "Unexpected size"); + std::memcpy(&input_[0], &input, sizeof(Mask4Type)); + + IntType result_[4]; + result_[0] = ~input_[0]; + result_[1] = ~input_[1]; + result_[2] = ~input_[2]; + result_[3] = ~input_[3]; + + Mask4Type result; + std::memcpy(&result, &result_[0], sizeof(Mask4Type)); + + return result; +} + template static void test_mask_impl() { @@ -119,6 +139,20 @@ static void test_mask_impl() CHECK(mask_get_w(mask) == ~IntType(0)); } + { + MaskType mask = mask_true(); + CHECK(mask_get_x(mask) == ~IntType(0)); + CHECK(mask_get_y(mask) == ~IntType(0)); + CHECK(mask_get_z(mask) == ~IntType(0)); + CHECK(mask_get_w(mask) == ~IntType(0)); + + mask = mask_false(); + CHECK(mask_get_x(mask) == IntType(0)); + CHECK(mask_get_y(mask) == IntType(0)); + CHECK(mask_get_z(mask) == IntType(0)); + CHECK(mask_get_w(mask) == IntType(0)); + } + { const MaskType mask0 = mask_set(IntType(0), ~IntType(0), IntType(0), ~IntType(0)); const MaskType mask1 = mask_set(IntType(0), IntType(0), IntType(0), IntType(0)); @@ -284,6 +318,10 @@ static void test_mask_impl() CHECK(mask_all_equal(mask_xor(mask0, mask1), reference_mask_xor(mask0, mask1))); CHECK(mask_all_equal(mask_xor(mask0, mask2), reference_mask_xor(mask0, mask2))); CHECK(mask_all_equal(mask_xor(mask1, mask2), reference_mask_xor(mask1, mask2))); + + CHECK(mask_all_equal(mask_not(mask0), reference_mask_not(mask0))); + CHECK(mask_all_equal(mask_not(mask1), reference_mask_not(mask1))); + CHECK(mask_all_equal(mask_not(mask2), reference_mask_not(mask2))); } } diff --git a/tests/sources/test_quat.cpp b/tests/sources/test_quat.cpp index 5befc866..ef4e7386 100644 --- a/tests/sources/test_quat.cpp +++ b/tests/sources/test_quat.cpp @@ -26,6 +26,8 @@ #include "catch2.impl.h" #include +#include +#include #include #include #include @@ -97,6 +99,7 @@ static void test_quat_impl(const FloatType threshold) using Vector4Type = typename related_types::vector4; using Float4Type = typename related_types::float4; using ScalarType = typename related_types::scalar; + using MaskType = typename related_types::mask4; const Vector4Type zero = vector_zero(); const QuatType identity = quat_identity(); @@ -504,6 +507,17 @@ static void test_quat_impl(const FloatType threshold) CHECK(quat_near_identity(quat_set(FloatType(0.0), FloatType(0.0), FloatType(0.0), FloatType(0.9999999)), FloatType(0.001)) == true); CHECK(quat_near_identity(quat_set(FloatType(0.0), FloatType(0.0), FloatType(0.0), FloatType(0.98)), FloatType(0.001)) == false); } + + { + QuatType quat0 = quat_set(FloatType(0.39564531008956383), FloatType(0.044254239301713752), FloatType(0.22768840967675355), FloatType(0.88863059760894492)); + QuatType quat1 = identity; + + MaskType all_true = mask_true(); + MaskType all_false = mask_false(); + + CHECK(quat_are_equal(quat_select(all_true, quat0, quat1), quat0)); + CHECK(quat_are_equal(quat_select(all_false, quat0, quat1), quat1)); + } } TEST_CASE("quatf math", "[math][quat]") diff --git a/tests/sources/test_vector4_impl.h b/tests/sources/test_vector4_impl.h index c36d781d..8927e063 100644 --- a/tests/sources/test_vector4_impl.h +++ b/tests/sources/test_vector4_impl.h @@ -842,6 +842,16 @@ void test_vector4_relational_impl(const FloatType threshold) CHECK((mask_get_z(vector_equal(test_value0, test_value0)) != 0) == (test_value0_flt[2] == test_value0_flt[2])); CHECK((mask_get_w(vector_equal(test_value0, test_value0)) != 0) == (test_value0_flt[3] == test_value0_flt[3])); + CHECK((mask_get_x(vector_not_equal(test_value0, test_value1)) != 0) != (test_value0_flt[0] == test_value1_flt[0])); + CHECK((mask_get_y(vector_not_equal(test_value0, test_value1)) != 0) != (test_value0_flt[1] == test_value1_flt[1])); + CHECK((mask_get_z(vector_not_equal(test_value0, test_value1)) != 0) != (test_value0_flt[2] == test_value1_flt[2])); + CHECK((mask_get_w(vector_not_equal(test_value0, test_value1)) != 0) != (test_value0_flt[3] == test_value1_flt[3])); + + CHECK((mask_get_x(vector_not_equal(test_value0, test_value0)) != 0) != (test_value0_flt[0] == test_value0_flt[0])); + CHECK((mask_get_y(vector_not_equal(test_value0, test_value0)) != 0) != (test_value0_flt[1] == test_value0_flt[1])); + CHECK((mask_get_z(vector_not_equal(test_value0, test_value0)) != 0) != (test_value0_flt[2] == test_value0_flt[2])); + CHECK((mask_get_w(vector_not_equal(test_value0, test_value0)) != 0) != (test_value0_flt[3] == test_value0_flt[3])); + CHECK((mask_get_x(vector_less_than(test_value0, test_value1)) != 0) == (test_value0_flt[0] < test_value1_flt[0])); CHECK((mask_get_y(vector_less_than(test_value0, test_value1)) != 0) == (test_value0_flt[1] < test_value1_flt[1])); CHECK((mask_get_z(vector_less_than(test_value0, test_value1)) != 0) == (test_value0_flt[2] < test_value1_flt[2])); @@ -1143,6 +1153,71 @@ void test_vector4_relational_impl(const FloatType threshold) CHECK(vector_any_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) == false); CHECK(vector_any_equal3(zero, zero) == true); + + CHECK(vector_all_not_equal(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(1.0)), zero) != false); + CHECK(vector_all_not_equal(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(1.0)), zero) != false); + CHECK(vector_all_not_equal(vector_set(FloatType(0.0), FloatType(0.0), FloatType(-1.0), FloatType(-1.0)), zero) == false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(-1.0)), zero) == false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(-1.0)), zero) == false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) == false); + CHECK(vector_all_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_all_not_equal(zero, zero) != true); + + CHECK(vector_all_not_equal2(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(vector_set(FloatType(0.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) != true); + CHECK(vector_all_not_equal2(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) == false); + CHECK(vector_all_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal2(zero, zero) != true); + + CHECK(vector_all_not_equal3(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal3(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal3(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal3(vector_set(FloatType(0.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) == false); + CHECK(vector_all_not_equal3(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) == false); + CHECK(vector_all_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(0.0)), zero) == false); + CHECK(vector_all_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_all_not_equal3(zero, zero) != true); + + CHECK(vector_any_not_equal(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(1.0)), zero) != false); + CHECK(vector_any_not_equal(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(1.0)), zero) != false); + CHECK(vector_any_not_equal(vector_set(FloatType(0.0), FloatType(-1.0), FloatType(-1.0), FloatType(-1.0)), zero) == true); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(-1.0)), zero) == true); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(-1.0)), zero) == true); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(-1.0)), zero) != false); + CHECK(vector_any_not_equal(zero, zero) != true); + + CHECK(vector_any_not_equal2(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(vector_set(FloatType(0.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal2(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal2(zero, zero) != true); + + CHECK(vector_any_not_equal3(vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal3(vector_set(FloatType(1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal3(vector_set(FloatType(-1.0), FloatType(1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal3(vector_set(FloatType(0.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal3(vector_set(FloatType(-1.0), FloatType(0.0), FloatType(-1.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(0.0), FloatType(0.0)), zero) == true); + CHECK(vector_any_not_equal3(vector_set(FloatType(-1.0), FloatType(-1.0), FloatType(-1.0), FloatType(0.0)), zero) != false); + CHECK(vector_any_not_equal3(zero, zero) != true); + CHECK(vector_all_near_equal(zero, zero, threshold) == true); CHECK(vector_all_near_equal(zero, vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(1.0)), FloatType(1.0001)) == true); CHECK(vector_all_near_equal(zero, vector_set(FloatType(1.0), FloatType(1.0), FloatType(1.0), FloatType(1.0)), FloatType(1.0)) == true);