Compare commits

..

11 Commits

Author SHA1 Message Date
orange 792fb13851 patch 2026-06-12 01:12:13 +03:00
orange 2d38387da9 fix 2026-06-12 01:05:14 +03:00
orange 5f14510e5b made constexpr cryengine camera & fromulas 2026-06-12 00:52:22 +03:00
orange 4a9125549f patch 2026-06-12 00:09:14 +03:00
orange d9acf5eea8 fix 2026-06-12 00:04:12 +03:00
orange 589f440e70 added gcem to pipelines 2026-06-11 23:54:53 +03:00
orange 854b50f317 added mat tests and triangle tests 2026-06-11 23:49:03 +03:00
orange a741fc1485 now add constexpr gcem tests for triangle and mat classes 2026-06-11 23:41:07 +03:00
orange a2be99be50 added more gcem to angle vec2,3 2026-06-11 23:20:18 +03:00
orange 00e7c564fd added gcem 2026-06-11 16:18:52 +03:00
orange 5d9dbec5b8 reverted fix 2026-06-10 15:22:31 +03:00
22 changed files with 503 additions and 200 deletions
+1 -1
View File
@@ -107,7 +107,7 @@ jobs:
-DOMATH_BUILD_TESTS=ON \ -DOMATH_BUILD_TESTS=ON \
-DOMATH_BUILD_BENCHMARK=OFF \ -DOMATH_BUILD_BENCHMARK=OFF \
-DOMATH_ENABLE_COVERAGE=${{ matrix.coverage == true && 'ON' || 'OFF' }} \ -DOMATH_ENABLE_COVERAGE=${{ matrix.coverage == true && 'ON' || 'OFF' }} \
-DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua" -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests;lua;gcem"
- name: Build - name: Build
shell: bash shell: bash
+10
View File
@@ -33,6 +33,7 @@ option(OMATH_ENABLE_FORCE_INLINE
option(OMATH_ENABLE_LUA option(OMATH_ENABLE_LUA
"omath bindings for lua" OFF) "omath bindings for lua" OFF)
option(OMATH_ENABLE_HOOKING "omath will HooksManager that can hook DirectX/OpenGL automatically" OFF) option(OMATH_ENABLE_HOOKING "omath will HooksManager that can hook DirectX/OpenGL automatically" OFF)
option(OMATH_USE_GCEM "omath will use gcem library to make more functions/methods constexpr" OFF)
if(VCPKG_MANIFEST_FEATURES) if(VCPKG_MANIFEST_FEATURES)
foreach(omath_feature IN LISTS VCPKG_MANIFEST_FEATURES) foreach(omath_feature IN LISTS VCPKG_MANIFEST_FEATURES)
@@ -50,6 +51,8 @@ if(VCPKG_MANIFEST_FEATURES)
set(OMATH_ENABLE_LUA ON) set(OMATH_ENABLE_LUA ON)
elseif(omath_feature STREQUAL "hooking") elseif(omath_feature STREQUAL "hooking")
set(OMATH_ENABLE_HOOKING ON) set(OMATH_ENABLE_HOOKING ON)
elseif (omath_feature STREQUAL "gcem")
set(OMATH_USE_GCEM ON)
endif() endif()
endforeach() endforeach()
@@ -80,6 +83,7 @@ if(${PROJECT_IS_TOP_LEVEL})
message(STATUS "[${PROJECT_NAME}]: Coverage feature status ${OMATH_ENABLE_COVERAGE}") message(STATUS "[${PROJECT_NAME}]: Coverage feature status ${OMATH_ENABLE_COVERAGE}")
message(STATUS "[${PROJECT_NAME}]: Valgrind feature status ${OMATH_ENABLE_VALGRIND}") message(STATUS "[${PROJECT_NAME}]: Valgrind feature status ${OMATH_ENABLE_VALGRIND}")
message(STATUS "[${PROJECT_NAME}]: Lua feature status ${OMATH_ENABLE_LUA}") message(STATUS "[${PROJECT_NAME}]: Lua feature status ${OMATH_ENABLE_LUA}")
message(STATUS "[${PROJECT_NAME}]: Gcem feature status ${OMATH_USE_GCEM}")
endif() endif()
if(OMATH_STATIC_MSVC_RUNTIME_LIBRARY) if(OMATH_STATIC_MSVC_RUNTIME_LIBRARY)
@@ -120,6 +124,12 @@ if (OMATH_ENABLE_HOOKING)
endif () endif ()
endif () endif ()
if (OMATH_USE_GCEM)
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_USE_GCEM)
find_package(gcem CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC gcem)
endif ()
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}") target_compile_definitions(${PROJECT_NAME} PUBLIC OMATH_VERSION="${PROJECT_VERSION}")
+2 -2
View File
@@ -57,7 +57,7 @@
"inherits": ["windows-base", "vcpkg-base"], "inherits": ["windows-base", "vcpkg-base"],
"cacheVariables": { "cacheVariables": {
"VCPKG_TARGET_TRIPLET": "x64-windows-static", "VCPKG_TARGET_TRIPLET": "x64-windows-static",
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;hooking", "VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;hooking;gcem",
"OMATH_STATIC_MSVC_RUNTIME_LIBRARY": "ON" "OMATH_STATIC_MSVC_RUNTIME_LIBRARY": "ON"
} }
}, },
@@ -239,7 +239,7 @@
"hidden": true, "hidden": true,
"inherits": ["darwin-base", "vcpkg-base"], "inherits": ["darwin-base", "vcpkg-base"],
"cacheVariables": { "cacheVariables": {
"VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;lua" "VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples;lua;gcem"
} }
}, },
{ {
+60 -10
View File
@@ -8,31 +8,81 @@
namespace omath::cry_engine namespace omath::cry_engine
{ {
[[nodiscard]] [[nodiscard]]
Vector3<float> forward_vector(const ViewAngles& angles) noexcept; inline OMATH_CONSTEXPR Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw)
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.roll)
* mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch);
}
[[nodiscard]] [[nodiscard]]
Vector3<float> right_vector(const ViewAngles& angles) noexcept; inline OMATH_CONSTEXPR Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
[[nodiscard]] [[nodiscard]]
Vector3<float> up_vector(const ViewAngles& angles) noexcept; inline OMATH_CONSTEXPR Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
[[nodiscard]] Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept; return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
[[nodiscard]] [[nodiscard]]
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept; inline OMATH_CONSTEXPR Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
[[nodiscard]] [[nodiscard]]
Vector3<float> extract_origin(const Mat4X4& mat) noexcept; inline OMATH_CONSTEXPR Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), right_vector(angles),
up_vector(angles), cam_origin);
}
[[nodiscard]] [[nodiscard]]
Vector3<float> extract_scale(const Mat4X4& mat) noexcept; inline OMATH_CONSTEXPR Vector3<float> extract_origin(const Mat4X4& mat) noexcept
{
return mat_extract_origin(mat);
}
[[nodiscard]] [[nodiscard]]
ViewAngles extract_rotation_angles(const Mat4X4& mat) noexcept; inline OMATH_CONSTEXPR Vector3<float> extract_scale(const Mat4X4& mat) noexcept
{
return mat_extract_scale(mat);
}
[[nodiscard]] [[nodiscard]]
Mat4X4 calc_perspective_projection_matrix(float field_of_view, float aspect_ratio, float near, float far, inline OMATH_CONSTEXPR ViewAngles extract_rotation_angles(const Mat4X4& mat) noexcept
NDCDepthRange ndc_depth_range = NDCDepthRange::ZERO_TO_ONE) noexcept; {
const auto angles = mat_extract_rotation_zyx(mat);
return {
PitchAngle::from_degrees(angles.x),
YawAngle::from_degrees(angles.z),
RollAngle::from_degrees(angles.y),
};
}
[[nodiscard]]
inline OMATH_CONSTEXPR Mat4X4 calc_perspective_projection_matrix(
const float field_of_view, const float aspect_ratio, const float near, const float far,
const NDCDepthRange ndc_depth_range = NDCDepthRange::ZERO_TO_ONE) noexcept
{
if (ndc_depth_range == NDCDepthRange::ZERO_TO_ONE)
return mat_perspective_left_handed_vertical_fov<float, MatStoreType::ROW_MAJOR, NDCDepthRange::ZERO_TO_ONE>(
field_of_view, aspect_ratio, near, far);
if (ndc_depth_range == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return mat_perspective_left_handed_vertical_fov<float, MatStoreType::ROW_MAJOR,
NDCDepthRange::NEGATIVE_ONE_TO_ONE>(
field_of_view, aspect_ratio, near, far);
std::unreachable();
}
template<class FloatingType> template<class FloatingType>
requires std::is_floating_point_v<FloatingType> requires std::is_floating_point_v<FloatingType>
@@ -4,21 +4,41 @@
#pragma once #pragma once
#include "omath/engines/cry_engine/formulas.hpp" #include "omath/engines/cry_engine/formulas.hpp"
#include "omath/internal/optional_constexpr_math.hpp"
#include "omath/projection/camera.hpp" #include "omath/projection/camera.hpp"
namespace omath::cry_engine namespace omath::cry_engine
{ {
class CameraTrait final class CameraTrait final
{ {
public: public:
[[nodiscard]] [[nodiscard]]
static ViewAngles calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept; OMATH_CONSTEXPR static ViewAngles calc_look_at_angle(const Vector3<float>& cam_origin,
const Vector3<float>& look_at) noexcept
{
const auto direction = (look_at - cam_origin).normalized();
#ifdef OMATH_USE_GCEM
return {PitchAngle::from_radians(gcem::asin(direction.z)),
YawAngle::from_radians(-gcem::atan2(direction.x, direction.y)), RollAngle::from_radians(0.f)};
#else
return {PitchAngle::from_radians(std::asin(direction.z)),
YawAngle::from_radians(-std::atan2(direction.x, direction.y)), RollAngle::from_radians(0.f)};
#endif
}
[[nodiscard]] [[nodiscard]]
static Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept; OMATH_CONSTEXPR static Mat4X4 calc_view_matrix(const ViewAngles& angles,
const Vector3<float>& cam_origin) noexcept
{
return cry_engine::calc_view_matrix(angles, cam_origin);
}
[[nodiscard]] [[nodiscard]]
static Mat4X4 calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port, OMATH_CONSTEXPR static Mat4X4
float near, float far, NDCDepthRange ndc_depth_range) noexcept; calc_projection_matrix(const projection::FieldOfView& fov, const projection::ViewPort& view_port,
const float near, const float far, const NDCDepthRange ndc_depth_range) noexcept
{
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
ndc_depth_range);
}
}; };
} // namespace omath::cry_engine } // namespace omath::cry_engine
@@ -0,0 +1,12 @@
//
// Created by orange on 6/11/2026.
//
#pragma once
#ifdef OMATH_USE_GCEM
#include <gcem.hpp>
#define OMATH_CONSTEXPR constexpr
#else
#define OMATH_CONSTEXPR
#endif
+56 -15
View File
@@ -10,6 +10,7 @@
#include <numeric> #include <numeric>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <type_traits>
#include <utility> #include <utility>
#ifdef OMATH_USE_AVX2 #ifdef OMATH_USE_AVX2
@@ -149,7 +150,8 @@ namespace omath
} }
} }
[[nodiscard("You must use element reference")]] constexpr Type& at(const size_t row_index, const size_t column_index) [[nodiscard("You must use element reference")]] constexpr Type& at(const size_t row_index,
const size_t column_index)
{ {
return const_cast<Type&>(std::as_const(*this).at(row_index, column_index)); return const_cast<Type&>(std::as_const(*this).at(row_index, column_index));
} }
@@ -176,6 +178,13 @@ namespace omath
operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const operator*(const Mat<Columns, OtherColumns, Type, StoreType>& other) const
{ {
#ifdef OMATH_USE_AVX2 #ifdef OMATH_USE_AVX2
if (std::is_constant_evaluated())
{
if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return cache_friendly_multiply_row_major(other);
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
return cache_friendly_multiply_col_major(other);
}
if constexpr (StoreType == MatStoreType::ROW_MAJOR) if constexpr (StoreType == MatStoreType::ROW_MAJOR)
return avx_multiply_row_major(other); return avx_multiply_row_major(other);
else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR) else if constexpr (StoreType == MatStoreType::COLUMN_MAJOR)
@@ -622,10 +631,14 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard("You must use extracted scale")]] [[nodiscard("You must use extracted scale")]]
Vector3<Type> mat_extract_scale(const Mat<4, 4, Type, St>& mat) noexcept OMATH_CONSTEXPR Vector3<Type> mat_extract_scale(const Mat<4, 4, Type, St>& mat) noexcept
{ {
auto column_length = [](const Type x, const Type y, const Type z) { auto column_length = [](const Type x, const Type y, const Type z) {
#ifdef OMATH_USE_GCEM
return static_cast<Type>(gcem::sqrt(x * x + y * y + z * z));
#else
return static_cast<Type>(std::sqrt(x * x + y * y + z * z)); return static_cast<Type>(std::sqrt(x * x + y * y + z * z));
#endif
}; };
const auto scale_x = column_length(mat.at(0, 0), mat.at(1, 0), mat.at(2, 0)); const auto scale_x = column_length(mat.at(0, 0), mat.at(1, 0), mat.at(2, 0));
@@ -635,9 +648,15 @@ namespace omath
constexpr auto epsilon = std::numeric_limits<Type>::epsilon(); constexpr auto epsilon = std::numeric_limits<Type>::epsilon();
return { return {
#ifdef OMATH_USE_GCEM
gcem::abs(scale_x) < epsilon ? Type{1} : scale_x,
gcem::abs(scale_y) < epsilon ? Type{1} : scale_y,
gcem::abs(scale_z) < epsilon ? Type{1} : scale_z,
#else
std::abs(scale_x) < epsilon ? Type{1} : scale_x, std::abs(scale_x) < epsilon ? Type{1} : scale_x,
std::abs(scale_y) < epsilon ? Type{1} : scale_y, std::abs(scale_y) < epsilon ? Type{1} : scale_y,
std::abs(scale_z) < epsilon ? Type{1} : scale_z, std::abs(scale_z) < epsilon ? Type{1} : scale_z,
#endif
}; };
} }
@@ -654,15 +673,21 @@ namespace omath
const auto m22 = mat.at(2, 2) / scale.z; const auto m22 = mat.at(2, 2) / scale.z;
return { return {
#ifdef OMATH_USE_GCEM
angles::radians_to_degrees(gcem::atan2(m21, m22)),
angles::radians_to_degrees(gcem::asin(std::clamp(-m20, Type{-1}, Type{1}))),
angles::radians_to_degrees(gcem::atan2(m10, m00)),
#else
angles::radians_to_degrees(std::atan2(m21, m22)), angles::radians_to_degrees(std::atan2(m21, m22)),
angles::radians_to_degrees(std::asin(std::clamp(-m20, Type{-1}, Type{1}))), angles::radians_to_degrees(std::asin(std::clamp(-m20, Type{-1}, Type{1}))),
angles::radians_to_degrees(std::atan2(m10, m00)), angles::radians_to_degrees(std::atan2(m10, m00)),
#endif
}; };
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard("You must use rotation matrix")]] [[nodiscard("You must use rotation matrix")]]
Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_x(const Angle& angle) noexcept
{ {
return return
{ {
@@ -675,7 +700,7 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard("You must use rotation matrix")]] [[nodiscard("You must use rotation matrix")]]
Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_y(const Angle& angle) noexcept
{ {
return return
{ {
@@ -688,7 +713,7 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, class Angle>
[[nodiscard("You must use rotation matrix")]] [[nodiscard("You must use rotation matrix")]]
Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept OMATH_CONSTEXPR Mat<4, 4, Type, St> mat_rotation_axis_z(const Angle& angle) noexcept
{ {
return return
{ {
@@ -701,7 +726,7 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR> template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR>
[[nodiscard("You must use camera view matrix")]] [[nodiscard("You must use camera view matrix")]]
static Mat<4, 4, Type, St> mat_camera_view(const Vector3<Type>& forward, const Vector3<Type>& right, OMATH_CONSTEXPR static Mat<4, 4, Type, St> mat_camera_view(const Vector3<Type>& forward, const Vector3<Type>& right,
const Vector3<Type>& up, const Vector3<Type>& camera_origin) noexcept const Vector3<Type>& up, const Vector3<Type>& camera_origin) noexcept
{ {
return Mat<4, 4, Type, St> return Mat<4, 4, Type, St>
@@ -715,12 +740,15 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use perspective matrix")]] [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_perspective_left_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio, Mat<4, 4, Type, St> mat_perspective_left_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio,
const Type near, const Type far) noexcept const Type near, const Type far) noexcept
{ {
#ifdef OMATH_USE_GCEM
const auto fov_half_tan = gcem::tan(angles::degrees_to_radians(field_of_view) / Type{2});
#else
const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2}); const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2});
#endif
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE) if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}}, return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}},
{Type{0}, Type{1} / fov_half_tan, Type{0}, Type{0}}, {Type{0}, Type{1} / fov_half_tan, Type{0}, Type{0}},
@@ -737,11 +765,15 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use perspective matrix")]] [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_perspective_right_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio, Mat<4, 4, Type, St> mat_perspective_right_handed_vertical_fov(const Type field_of_view, const Type aspect_ratio,
const Type near, const Type far) noexcept const Type near, const Type far) noexcept
{ {
#ifdef OMATH_USE_GCEM
const auto fov_half_tan = gcem::tan(angles::degrees_to_radians(field_of_view) / Type{2});
#else
const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2}); const auto fov_half_tan = std::tan(angles::degrees_to_radians(field_of_view) / Type{2});
#endif
if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE) if constexpr (DepthRange == NDCDepthRange::ZERO_TO_ONE)
return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}}, return {{Type{1} / (aspect_ratio * fov_half_tan), Type{0}, Type{0}, Type{0}},
@@ -762,12 +794,16 @@ namespace omath
// X and Y scales derived as: X = 1 / tan(hfov/2), Y = aspect / tan(hfov/2). // X and Y scales derived as: X = 1 / tan(hfov/2), Y = aspect / tan(hfov/2).
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use perspective matrix")]] [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_perspective_left_handed_horizontal_fov(const Type horizontal_fov, Mat<4, 4, Type, St> mat_perspective_left_handed_horizontal_fov(const Type horizontal_fov,
const Type aspect_ratio, const Type near, const Type aspect_ratio, const Type near,
const Type far) noexcept const Type far) noexcept
{ {
#ifdef OMATH_USE_GCEM
const auto inv_tan_half_hfov = Type{1} / gcem::tan(angles::degrees_to_radians(horizontal_fov) / Type{2});
#else
const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2});
#endif
const auto x_axis = inv_tan_half_hfov; const auto x_axis = inv_tan_half_hfov;
const auto y_axis = inv_tan_half_hfov * aspect_ratio; const auto y_axis = inv_tan_half_hfov * aspect_ratio;
@@ -787,12 +823,17 @@ namespace omath
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use perspective matrix")]] [[nodiscard("You must use perspective matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_perspective_right_handed_horizontal_fov(const Type horizontal_fov, Mat<4, 4, Type, St> mat_perspective_right_handed_horizontal_fov(const Type horizontal_fov,
const Type aspect_ratio, const Type near, const Type aspect_ratio, const Type near,
const Type far) noexcept const Type far) noexcept
{ {
#ifdef OMATH_USE_GCEM
const auto inv_tan_half_hfov = Type{1} / gcem::tan(angles::degrees_to_radians(horizontal_fov) / Type{2});
#else
const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2}); const auto inv_tan_half_hfov = Type{1} / std::tan(angles::degrees_to_radians(horizontal_fov) / Type{2});
#endif
const auto x_axis = inv_tan_half_hfov; const auto x_axis = inv_tan_half_hfov;
const auto y_axis = inv_tan_half_hfov * aspect_ratio; const auto y_axis = inv_tan_half_hfov * aspect_ratio;
@@ -811,7 +852,7 @@ namespace omath
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use ortho matrix")]] [[nodiscard("You must use ortho matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top, Mat<4, 4, Type, St> mat_ortho_left_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept const Type near, const Type far) noexcept
{ {
@@ -836,7 +877,7 @@ namespace omath
} }
template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR, template<class Type = float, MatStoreType St = MatStoreType::ROW_MAJOR,
NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE> NDCDepthRange DepthRange = NDCDepthRange::NEGATIVE_ONE_TO_ONE>
[[nodiscard("You must use ortho matrix")]] [[nodiscard("You must use ortho matrix")]] OMATH_CONSTEXPR
Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top, Mat<4, 4, Type, St> mat_ortho_right_handed(const Type left, const Type right, const Type bottom, const Type top,
const Type near, const Type far) noexcept const Type near, const Type far) noexcept
{ {
@@ -860,7 +901,7 @@ namespace omath
std::unreachable(); std::unreachable();
} }
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR> template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up) OMATH_CONSTEXPR Mat<4, 4, T, St> mat_look_at_left_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
{ {
const Vector3<T> f = (center - eye).normalized(); const Vector3<T> f = (center - eye).normalized();
const Vector3<T> s = f.cross(up).normalized(); const Vector3<T> s = f.cross(up).normalized();
@@ -869,7 +910,7 @@ namespace omath
} }
template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR> template<class T = float, MatStoreType St = MatStoreType::COLUMN_MAJOR>
Mat<4, 4, T, St>mat_look_at_right_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up) OMATH_CONSTEXPR Mat<4, 4, T, St> mat_look_at_right_handed(const Vector3<T>& eye, const Vector3<T>& center, const Vector3<T>& up)
{ {
const Vector3<T> f = (center - eye).normalized(); const Vector3<T> f = (center - eye).normalized();
const Vector3<T> s = f.cross(up).normalized(); const Vector3<T> s = f.cross(up).normalized();
+7 -3
View File
@@ -2,8 +2,8 @@
// Created by Orange on 11/13/2024. // Created by Orange on 11/13/2024.
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include "vector3.hpp" #include "vector3.hpp"
namespace omath namespace omath
{ {
/* /*
@@ -40,13 +40,13 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
Vector::ContainedType side_a_length() const OMATH_CONSTEXPR Vector::ContainedType side_a_length() const
{ {
return m_vertex1.distance_to(m_vertex2); return m_vertex1.distance_to(m_vertex2);
} }
[[nodiscard]] [[nodiscard]]
Vector::ContainedType side_b_length() const OMATH_CONSTEXPR Vector::ContainedType side_b_length() const
{ {
return m_vertex3.distance_to(m_vertex2); return m_vertex3.distance_to(m_vertex2);
} }
@@ -69,7 +69,11 @@ namespace omath
const auto side_b = side_b_length(); const auto side_b = side_b_length();
const auto hypot_value = hypot(); const auto hypot_value = hypot();
#ifdef OMATH_USE_GCEM
return gcem::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f;
#else
return std::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f; return std::abs(side_a * side_a + side_b * side_b - hypot_value * hypot_value) <= 0.0001f;
#endif
} }
[[nodiscard]] [[nodiscard]]
constexpr Vector side_b_vector() const constexpr Vector side_b_vector() const
+20 -7
View File
@@ -3,6 +3,7 @@
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <tuple> #include <tuple>
@@ -116,9 +117,13 @@ namespace omath
// Basic vector operations // Basic vector operations
[[nodiscard("You must use distance")]] [[nodiscard("You must use distance")]]
Type distance_to(const Vector2& other) const noexcept OMATH_CONSTEXPR Type distance_to(const Vector2& other) const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(distance_to_sqr(other));
#else
return std::sqrt(distance_to_sqr(other)); return std::sqrt(distance_to_sqr(other));
#endif
} }
[[nodiscard("You must use squared distance")]] [[nodiscard("You must use squared distance")]]
@@ -136,7 +141,11 @@ namespace omath
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard("You must use length")]] constexpr Type length() const noexcept [[nodiscard("You must use length")]] constexpr Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::hypot(this->x, this->y);
#else
return std::hypot(this->x, this->y); return std::hypot(this->x, this->y);
#endif
} }
[[nodiscard("You must use normalized vector")]] constexpr Vector2 normalized() const noexcept [[nodiscard("You must use normalized vector")]] constexpr Vector2 normalized() const noexcept
@@ -146,13 +155,17 @@ namespace omath
} }
#else #else
[[nodiscard("You must use length")]] [[nodiscard("You must use length")]]
Type length() const noexcept OMATH_CONSTEXPR Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::hypot(x, y);
#else
return std::hypot(x, y); return std::hypot(x, y);
#endif
} }
[[nodiscard("You must use normalized vector")]] [[nodiscard("You must use normalized vector")]]
Vector2 normalized() const noexcept OMATH_CONSTEXPR Vector2 normalized() const noexcept
{ {
const Type len = length(); const Type len = length();
return len > static_cast<Type>(0) ? *this / len : *this; return len > static_cast<Type>(0) ? *this / len : *this;
@@ -216,24 +229,24 @@ namespace omath
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator<(const Vector2& other) const noexcept
{ {
return length() < other.length(); return length() < other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator>(const Vector2& other) const noexcept
{ {
return length() > other.length(); return length() > other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<=(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator<=(const Vector2& other) const noexcept
{ {
return length() <= other.length(); return length() <= other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>=(const Vector2& other) const noexcept OMATH_CONSTEXPR bool operator>=(const Vector2& other) const noexcept
{ {
return length() >= other.length(); return length() >= other.length();
} }
+29 -16
View File
@@ -140,20 +140,24 @@ namespace omath
} }
#ifndef _MSC_VER #ifndef _MSC_VER
[[nodiscard("You must use length")]] constexpr Type length() const [[nodiscard("You must use length")]] constexpr Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(this->x * this->x + this->y * this->y + z * z);
#else
return std::hypot(this->x, this->y, z); return std::hypot(this->x, this->y, z);
#endif
} }
[[nodiscard("You must use 2D length")]] constexpr Type length_2d() const [[nodiscard("You must use 2D length")]] constexpr Type length_2d() const noexcept
{ {
return Vector2<Type>::length(); return Vector2<Type>::length();
} }
[[nodiscard("You must use distance")]] Type distance_to(const Vector3& other) const [[nodiscard("You must use distance")]] OMATH_CONSTEXPR Type distance_to(const Vector3& other) const noexcept
{ {
return (*this - other).length(); return (*this - other).length();
} }
[[nodiscard("You must use normalized vector")]] constexpr Vector3 normalized() const [[nodiscard("You must use normalized vector")]] constexpr Vector3 normalized() const noexcept
{ {
const Type length_value = this->length(); const Type length_value = this->length();
@@ -161,13 +165,17 @@ namespace omath
} }
#else #else
[[nodiscard("You must use length")]] [[nodiscard("You must use length")]]
Type length() const noexcept OMATH_CONSTEXPR Type length() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sqrt(this->x * this->x + this->y * this->y + this->z * this->z);
#else
return std::hypot(this->x, this->y, z); return std::hypot(this->x, this->y, z);
#endif
} }
[[nodiscard("You must use normalized vector")]] [[nodiscard("You must use normalized vector")]]
Vector3 normalized() const noexcept OMATH_CONSTEXPR Vector3 normalized() const noexcept
{ {
const Type len = this->length(); const Type len = this->length();
@@ -175,13 +183,13 @@ namespace omath
} }
[[nodiscard("You must use 2D length")]] [[nodiscard("You must use 2D length")]]
Type length_2d() const noexcept OMATH_CONSTEXPR Type length_2d() const noexcept
{ {
return Vector2<Type>::length(); return Vector2<Type>::length();
} }
[[nodiscard("You must use distance")]] [[nodiscard("You must use distance")]]
Type distance_to(const Vector3& v_other) const noexcept OMATH_CONSTEXPR Type distance_to(const Vector3& v_other) const noexcept
{ {
return (*this - v_other).length(); return (*this - v_other).length();
} }
@@ -249,24 +257,28 @@ namespace omath
} }
[[nodiscard("You must use direction check result")]] [[nodiscard("You must use direction check result")]]
bool point_to_same_direction(const Vector3& other) const OMATH_CONSTEXPR bool point_to_same_direction(const Vector3& other) const
{ {
return dot(other) > static_cast<Type>(0); return dot(other) > static_cast<Type>(0);
} }
[[nodiscard("You must use angle between vectors")]] [[nodiscard("You must use angle between vectors")]]
std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error> OMATH_CONSTEXPR std::expected<Angle<float, 0.f, 180.f, AngleFlags::Clamped>, Vector3Error>
angle_between(const Vector3& other) const noexcept angle_between(const Vector3& other) const noexcept
{ {
const auto bottom = length() * other.length(); const auto bottom = length() * other.length();
if (bottom == static_cast<Type>(0)) if (bottom == static_cast<Type>(0))
return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE); return std::unexpected(Vector3Error::IMPOSSIBLE_BETWEEN_ANGLE);
#ifdef OMATH_USE_GCEM
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(gcem::acos(dot(other) / bottom));
#else
return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom)); return Angle<float, 0.f, 180.f, AngleFlags::Clamped>::from_radians(std::acos(dot(other) / bottom));
#endif
} }
[[nodiscard("You must use perpendicularity check result")]] [[nodiscard("You must use perpendicularity check result")]]
bool is_perpendicular(const Vector3& other, Type epsilon = static_cast<Type>(0.0001)) const noexcept OMATH_CONSTEXPR bool is_perpendicular(const Vector3& other,
Type epsilon = static_cast<Type>(0.0001)) const noexcept
{ {
if (const auto angle = angle_between(other)) if (const auto angle = angle_between(other))
return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon; return std::abs(angle->as_degrees() - static_cast<Type>(90)) <= epsilon;
@@ -287,25 +299,25 @@ namespace omath
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator<(const Vector3& other) const noexcept
{ {
return length() < other.length(); return length() < other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator>(const Vector3& other) const noexcept
{ {
return length() > other.length(); return length() > other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator<=(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator<=(const Vector3& other) const noexcept
{ {
return length() <= other.length(); return length() <= other.length();
} }
[[nodiscard("You must use comparison result")]] [[nodiscard("You must use comparison result")]]
bool operator>=(const Vector3& other) const noexcept OMATH_CONSTEXPR bool operator>=(const Vector3& other) const noexcept
{ {
return length() >= other.length(); return length() >= other.length();
} }
@@ -320,6 +332,7 @@ namespace omath
template<> struct std::hash<omath::Vector3<float>> template<> struct std::hash<omath::Vector3<float>>
{ {
// NOTE: Cannot be constexpr because of MSVC
[[nodiscard("You must use hash value")]] [[nodiscard("You must use hash value")]]
std::size_t operator()(const omath::Vector3<float>& vec) const noexcept std::size_t operator()(const omath::Vector3<float>& vec) const noexcept
{ {
+26 -5
View File
@@ -3,6 +3,7 @@
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include "omath/trigonometry/angles.hpp" #include "omath/trigonometry/angles.hpp"
#include <algorithm> #include <algorithm>
#include <format> #include <format>
@@ -70,31 +71,51 @@ namespace omath
} }
[[nodiscard]] [[nodiscard]]
Type sin() const noexcept OMATH_CONSTEXPR Type sin() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::sin(as_radians());
#else
return std::sin(as_radians()); return std::sin(as_radians());
#endif
} }
[[nodiscard]] [[nodiscard]]
Type cos() const noexcept OMATH_CONSTEXPR Type cos() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::cos(as_radians());
#else
return std::cos(as_radians()); return std::cos(as_radians());
#endif
} }
[[nodiscard]] [[nodiscard]]
Type tan() const noexcept OMATH_CONSTEXPR Type tan() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::tan(as_radians());
#else
return std::tan(as_radians()); return std::tan(as_radians());
#endif
} }
[[nodiscard]] [[nodiscard]]
Type atan() const noexcept OMATH_CONSTEXPR Type atan() const noexcept
{ {
#ifdef OMATH_USE_GCEM
return gcem::atan(as_radians());
#else
return std::atan(as_radians()); return std::atan(as_radians());
#endif
} }
[[nodiscard]] [[nodiscard]]
Type cot() const noexcept OMATH_CONSTEXPR Type cot() const noexcept
{ {
return cos() / sin(); return cos() / sin();
} }
+6 -1
View File
@@ -3,6 +3,7 @@
// //
#pragma once #pragma once
#include "omath/internal/optional_constexpr_math.hpp"
#include <cmath> #include <cmath>
#include <numbers> #include <numbers>
@@ -47,14 +48,18 @@ namespace omath::angles
template<class Type> template<class Type>
requires std::is_arithmetic_v<Type> requires std::is_arithmetic_v<Type>
[[nodiscard]] Type wrap_angle(const Type& angle, const Type& min, const Type& max) noexcept [[nodiscard]] OMATH_CONSTEXPR Type wrap_angle(const Type& angle, const Type& min, const Type& max) noexcept
{ {
if (angle <= max && angle >= min) if (angle <= max && angle >= min)
return angle; return angle;
const Type range = max - min; const Type range = max - min;
#ifdef OMATH_USE_GCEM
Type wrapped_angle = gcem::fmod(angle - min, range);
#else
Type wrapped_angle = std::fmod(angle - min, range); Type wrapped_angle = std::fmod(angle - min, range);
#endif
if (wrapped_angle < 0) if (wrapped_angle < 0)
wrapped_angle += range; wrapped_angle += range;
-70
View File
@@ -1,70 +0,0 @@
//
// Created by Vlad on 3/22/2025.
//
#include "omath/engines/cry_engine/formulas.hpp"
namespace omath::cry_engine
{
Vector3<float> forward_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_forward);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> right_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_right);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Vector3<float> up_vector(const ViewAngles& angles) noexcept
{
const auto vec = rotation_matrix(angles) * mat_column_from_vector(k_abs_up);
return {vec.at(0, 0), vec.at(1, 0), vec.at(2, 0)};
}
Mat4X4 calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return mat_camera_view<float, MatStoreType::ROW_MAJOR>(forward_vector(angles), right_vector(angles),
up_vector(angles), cam_origin);
}
Mat4X4 rotation_matrix(const ViewAngles& angles) noexcept
{
return mat_rotation_axis_z<float, MatStoreType::ROW_MAJOR>(angles.yaw)
* mat_rotation_axis_y<float, MatStoreType::ROW_MAJOR>(angles.roll)
* mat_rotation_axis_x<float, MatStoreType::ROW_MAJOR>(angles.pitch);
}
Vector3<float> extract_origin(const Mat4X4& mat) noexcept
{
return mat_extract_origin(mat);
}
Vector3<float> extract_scale(const Mat4X4& mat) noexcept
{
return mat_extract_scale(mat);
}
ViewAngles extract_rotation_angles(const Mat4X4& mat) noexcept
{
const auto angles = mat_extract_rotation_zyx(mat);
return {
PitchAngle::from_degrees(angles.x),
YawAngle::from_degrees(angles.z),
RollAngle::from_degrees(angles.y),
};
}
Mat4X4 calc_perspective_projection_matrix(const float field_of_view, const float aspect_ratio, const float near,
const float far, const NDCDepthRange ndc_depth_range) noexcept
{
if (ndc_depth_range == NDCDepthRange::ZERO_TO_ONE)
return mat_perspective_left_handed_vertical_fov<float, MatStoreType::ROW_MAJOR, NDCDepthRange::ZERO_TO_ONE>(
field_of_view, aspect_ratio, near, far);
if (ndc_depth_range == NDCDepthRange::NEGATIVE_ONE_TO_ONE)
return mat_perspective_left_handed_vertical_fov<float, MatStoreType::ROW_MAJOR, NDCDepthRange::NEGATIVE_ONE_TO_ONE>(
field_of_view, aspect_ratio, near, far);
std::unreachable();
}
} // namespace omath::cry_engine
@@ -1,27 +0,0 @@
//
// Created by Vlad on 8/11/2025.
//
#include "omath/engines/cry_engine/traits/camera_trait.hpp"
namespace omath::cry_engine
{
ViewAngles CameraTrait::calc_look_at_angle(const Vector3<float>& cam_origin, const Vector3<float>& look_at) noexcept
{
const auto direction = (look_at - cam_origin).normalized();
return {PitchAngle::from_radians(std::asin(direction.z)),
YawAngle::from_radians(-std::atan2(direction.x, direction.y)), RollAngle::from_radians(0.f)};
}
Mat4X4 CameraTrait::calc_view_matrix(const ViewAngles& angles, const Vector3<float>& cam_origin) noexcept
{
return cry_engine::calc_view_matrix(angles, cam_origin);
}
Mat4X4 CameraTrait::calc_projection_matrix(const projection::FieldOfView& fov,
const projection::ViewPort& view_port, const float near,
const float far, const NDCDepthRange ndc_depth_range) noexcept
{
return calc_perspective_projection_matrix(fov.as_degrees(), view_port.aspect_ratio(), near, far,
ndc_depth_range);
}
} // namespace omath::cry_engine
+1 -1
View File
@@ -474,7 +474,7 @@ namespace omath
{ {
const auto* section = section_table + i; const auto* section = section_table + i;
if (std::string_view{section->name, sizeof(section->name)} != target_section_name if (std::string_view{section->name} != target_section_name
|| section->size_raw_data == 0) || section->size_raw_data == 0)
continue; continue;
+102 -16
View File
@@ -9,6 +9,98 @@
#include <ranges> #include <ranges>
using namespace omath; using namespace omath;
#ifdef OMATH_USE_GCEM
namespace
{
constexpr bool close_to(const float actual, const float expected, const float epsilon)
{
const float diff = actual - expected;
return (diff < 0.0f ? -diff : diff) <= epsilon;
}
constexpr bool vec_close_to(const Vector3<float>& actual, const Vector3<float>& expected, const float epsilon)
{
return close_to(actual.x, expected.x, epsilon) && close_to(actual.y, expected.y, epsilon)
&& close_to(actual.z, expected.z, epsilon);
}
} // namespace
static_assert(
[]
{
constexpr omath::cry_engine::ViewAngles angles{};
constexpr auto forward = omath::cry_engine::forward_vector(angles);
constexpr auto right = omath::cry_engine::right_vector(angles);
constexpr auto up = omath::cry_engine::up_vector(angles);
constexpr auto rotation = omath::cry_engine::rotation_matrix(angles);
return vec_close_to(forward, omath::cry_engine::k_abs_forward, 1e-5f)
&& vec_close_to(right, omath::cry_engine::k_abs_right, 1e-5f)
&& vec_close_to(up, omath::cry_engine::k_abs_up, 1e-5f) && close_to(rotation.at(0, 0), 1.0f, 1e-5f)
&& close_to(rotation.at(1, 1), 1.0f, 1e-5f) && close_to(rotation.at(2, 2), 1.0f, 1e-5f)
&& close_to(rotation.at(3, 3), 1.0f, 1e-5f);
}(),
"CryEngine basis vectors should be constexpr with gcem");
static_assert(
[]
{
constexpr auto view = omath::cry_engine::calc_view_matrix({}, {});
return close_to(view.at(0, 0), 1.0f, 1e-5f) && close_to(view.at(1, 2), 1.0f, 1e-5f)
&& close_to(view.at(2, 1), 1.0f, 1e-5f) && close_to(view.at(3, 3), 1.0f, 1e-5f);
}(),
"CryEngine view matrix should be constexpr with gcem");
static_assert(
[]
{
constexpr auto transform = mat_translation<float, MatStoreType::ROW_MAJOR>({1.0f, 2.0f, 3.0f})
* mat_scale<float, MatStoreType::ROW_MAJOR>({2.0f, 3.0f, 4.0f});
constexpr auto origin = omath::cry_engine::extract_origin(transform);
constexpr auto scale = omath::cry_engine::extract_scale(transform);
return vec_close_to(origin, {1.0f, 2.0f, 3.0f}, 1e-5f) && vec_close_to(scale, {2.0f, 3.0f, 4.0f}, 1e-5f);
}(),
"CryEngine transform extraction should be constexpr with gcem");
static_assert(
[]
{
constexpr auto projection = omath::cry_engine::calc_perspective_projection_matrix(
90.0f, 1.0f, 1.0f, 11.0f, NDCDepthRange::ZERO_TO_ONE);
return close_to(projection.at(0, 0), 1.0f, 1e-5f) && close_to(projection.at(1, 1), 1.0f, 1e-5f)
&& close_to(projection.at(2, 2), 1.1f, 1e-5f) && close_to(projection.at(2, 3), -1.1f, 1e-5f)
&& close_to(projection.at(3, 2), 1.0f, 1e-5f);
}(),
"CryEngine projection matrix should be constexpr with gcem");
static_assert(
[]
{
constexpr auto angles =
omath::cry_engine::CameraTrait::calc_look_at_angle({}, omath::cry_engine::k_abs_forward);
constexpr auto view = omath::cry_engine::CameraTrait::calc_view_matrix(angles, {});
constexpr auto projection = omath::cry_engine::CameraTrait::calc_projection_matrix(
projection::FieldOfView::from_degrees(90.0f), {1.0f, 1.0f}, 1.0f, 11.0f,
NDCDepthRange::ZERO_TO_ONE);
return close_to(angles.pitch.as_degrees(), 0.0f, 1e-5f) && close_to(angles.yaw.as_degrees(), 0.0f, 1e-5f)
&& close_to(angles.roll.as_degrees(), 0.0f, 1e-5f) && close_to(view.at(0, 0), 1.0f, 1e-5f)
&& close_to(view.at(2, 1), 1.0f, 1e-5f) && close_to(projection.at(0, 0), 1.0f, 1e-5f)
&& close_to(projection.at(1, 1), 1.0f, 1e-5f) && close_to(projection.at(2, 2), 1.1f, 1e-5f)
&& close_to(projection.at(2, 3), -1.1f, 1e-5f) && close_to(projection.at(3, 2), 1.0f, 1e-5f);
}(),
"CryEngine CameraTrait should be constexpr with gcem");
static_assert(omath::cry_engine::units_to_centimeters(100.0f) == 1.0f);
static_assert(omath::cry_engine::units_to_meters(2.0f) == 2.0f);
static_assert(omath::cry_engine::units_to_kilometers(2000.0f) == 2.0f);
static_assert(omath::cry_engine::centimeters_to_units(1.0f) == 100.0f);
static_assert(omath::cry_engine::meters_to_units(2.0f) == 2.0f);
static_assert(omath::cry_engine::kilometers_to_units(2.0f) == 2000.0f);
#endif
TEST(unit_test_cry_engine, look_at_forward) TEST(unit_test_cry_engine, look_at_forward)
{ {
const auto angles = cry_engine::CameraTrait::calc_look_at_angle({}, cry_engine::k_abs_forward); const auto angles = cry_engine::CameraTrait::calc_look_at_angle({}, cry_engine::k_abs_forward);
@@ -251,11 +343,9 @@ TEST(unit_test_cry_engine, ViewAnglesAsVector3Zero)
TEST(unit_test_cry_engine, ViewAnglesAsVector3Values) TEST(unit_test_cry_engine, ViewAnglesAsVector3Values)
{ {
const omath::cry_engine::ViewAngles angles{ const omath::cry_engine::ViewAngles angles{omath::cry_engine::PitchAngle::from_degrees(45.f),
omath::cry_engine::PitchAngle::from_degrees(45.f), omath::cry_engine::YawAngle::from_degrees(-90.f),
omath::cry_engine::YawAngle::from_degrees(-90.f), omath::cry_engine::RollAngle::from_degrees(30.f)};
omath::cry_engine::RollAngle::from_degrees(30.f)
};
const auto vec = angles.as_vector3(); const auto vec = angles.as_vector3();
EXPECT_FLOAT_EQ(vec.x, 45.f); EXPECT_FLOAT_EQ(vec.x, 45.f);
@@ -266,11 +356,9 @@ TEST(unit_test_cry_engine, ViewAnglesAsVector3Values)
TEST(unit_test_cry_engine, ViewAnglesAsVector3ClampedPitch) TEST(unit_test_cry_engine, ViewAnglesAsVector3ClampedPitch)
{ {
// Pitch is clamped to [-90, 90] // Pitch is clamped to [-90, 90]
const omath::cry_engine::ViewAngles angles{ const omath::cry_engine::ViewAngles angles{omath::cry_engine::PitchAngle::from_degrees(120.f),
omath::cry_engine::PitchAngle::from_degrees(120.f), omath::cry_engine::YawAngle::from_degrees(0.f),
omath::cry_engine::YawAngle::from_degrees(0.f), omath::cry_engine::RollAngle::from_degrees(0.f)};
omath::cry_engine::RollAngle::from_degrees(0.f)
};
const auto vec = angles.as_vector3(); const auto vec = angles.as_vector3();
EXPECT_FLOAT_EQ(vec.x, 90.f); EXPECT_FLOAT_EQ(vec.x, 90.f);
@@ -279,12 +367,10 @@ TEST(unit_test_cry_engine, ViewAnglesAsVector3ClampedPitch)
TEST(unit_test_cry_engine, ViewAnglesAsVector3NormalizedYaw) TEST(unit_test_cry_engine, ViewAnglesAsVector3NormalizedYaw)
{ {
// Yaw is normalized to [-180, 180], 270 wraps to -90 // Yaw is normalized to [-180, 180], 270 wraps to -90
const omath::cry_engine::ViewAngles angles{ const omath::cry_engine::ViewAngles angles{omath::cry_engine::PitchAngle::from_degrees(0.f),
omath::cry_engine::PitchAngle::from_degrees(0.f), omath::cry_engine::YawAngle::from_degrees(270.f),
omath::cry_engine::YawAngle::from_degrees(270.f), omath::cry_engine::RollAngle::from_degrees(0.f)};
omath::cry_engine::RollAngle::from_degrees(0.f)
};
const auto vec = angles.as_vector3(); const auto vec = angles.as_vector3();
EXPECT_NEAR(vec.y, -90.f, 0.01f); EXPECT_NEAR(vec.y, -90.f, 0.01f);
} }
+17 -1
View File
@@ -2,10 +2,10 @@
// Created by Orange on 11/30/2024. // Created by Orange on 11/30/2024.
// //
#include <omath/trigonometry/angle.hpp>
#include <cmath> #include <cmath>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <numbers> #include <numbers>
#include <omath/trigonometry/angle.hpp>
using namespace omath; using namespace omath;
@@ -19,6 +19,14 @@ namespace
constexpr float k_eps = 1e-5f; constexpr float k_eps = 1e-5f;
#ifdef OMATH_USE_GCEM
constexpr bool close_to(const float actual, const float expected, const float epsilon)
{
const float diff = actual - expected;
return (diff < 0.0f ? -diff : diff) <= epsilon;
}
#endif
} // namespace } // namespace
// ---------- Construction / factories ---------- // ---------- Construction / factories ----------
@@ -190,3 +198,11 @@ TEST(UnitTestAngle, BinaryMinus_ReturnsWrappedDiff)
const Deg c = a - b; // expect 340° const Deg c = a - b; // expect 340°
EXPECT_FLOAT_EQ(c.as_degrees(), 340.0f); EXPECT_FLOAT_EQ(c.as_degrees(), 340.0f);
} }
#ifdef OMATH_USE_GCEM
static_assert(close_to(Pitch::from_degrees(0.0f).sin(), 0.0f, k_eps), "Sin should be constexpr with gcem");
static_assert(close_to(Pitch::from_degrees(0.0f).cos(), 1.0f, k_eps), "Cos should be constexpr with gcem");
static_assert(close_to(Pitch::from_degrees(45.0f).tan(), 1.0f, 1e-4f), "Tan should be constexpr with gcem");
static_assert(close_to(Pitch::from_degrees(45.0f).cot(), 1.0f, 1e-4f), "Cot should be constexpr with gcem");
static_assert(close_to(Pitch::from_degrees(45.0f).atan(), 0.66577375f, 1e-6f), "Atan should be constexpr with gcem");
#endif
+59 -1
View File
@@ -1,11 +1,25 @@
// UnitTestMat.cpp // UnitTestMat.cpp
#include "omath/linear_algebra/mat.hpp" #include "omath/linear_algebra/mat.hpp"
#include "omath/linear_algebra/vector3.hpp" #include "omath/linear_algebra/vector3.hpp"
#include "omath/trigonometry/angle.hpp"
#include "omath/trigonometry/angles.hpp" #include "omath/trigonometry/angles.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
using namespace omath; using namespace omath;
#ifdef OMATH_USE_GCEM
namespace
{
using Pitch = Angle<float, static_cast<float>(-90), static_cast<float>(90), AngleFlags::Clamped>;
constexpr bool close_to(const float actual, const float expected, const float epsilon)
{
const float diff = actual - expected;
return (diff < 0.0f ? -diff : diff) <= epsilon;
}
} // namespace
#endif
class UnitTestMat : public ::testing::Test class UnitTestMat : public ::testing::Test
{ {
protected: protected:
@@ -522,4 +536,48 @@ TEST(UnitTestMatStandalone, MatOrthoNegativeOneToOneDefault)
NDCDepthRange::NEGATIVE_ONE_TO_ONE>(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f); NDCDepthRange::NEGATIVE_ONE_TO_ONE>(-1.f, 1.f, -1.f, 1.f, 0.1f, 100.f);
EXPECT_EQ(ortho_default, ortho_explicit); EXPECT_EQ(ortho_default, ortho_explicit);
} }
#ifdef OMATH_USE_GCEM
static_assert(
[]
{
constexpr auto scale = mat_extract_scale(mat_scale(Vector3{2.0f, 3.0f, 4.0f}));
return close_to(scale.x, 2.0f, 1e-5f) && close_to(scale.y, 3.0f, 1e-5f) && close_to(scale.z, 4.0f, 1e-5f);
}(),
"Mat scale extraction should be constexpr with gcem");
static_assert(
[]
{
constexpr auto rotation = mat_rotation_axis_z<float>(Pitch::from_degrees(90.0f));
return close_to(rotation.at(0, 0), 0.0f, 1e-5f) && close_to(rotation.at(0, 1), -1.0f, 1e-5f)
&& close_to(rotation.at(1, 0), 1.0f, 1e-5f) && close_to(rotation.at(1, 1), 0.0f, 1e-5f)
&& close_to(rotation.at(2, 2), 1.0f, 1e-5f) && close_to(rotation.at(3, 3), 1.0f, 1e-5f);
}(),
"Mat rotation should be constexpr with gcem");
static_assert(
[]
{
constexpr auto projection =
mat_perspective_left_handed_vertical_fov<float, MatStoreType::ROW_MAJOR,
NDCDepthRange::ZERO_TO_ONE>(90.0f, 1.0f, 1.0f, 11.0f);
return close_to(projection.at(0, 0), 1.0f, 1e-5f) && close_to(projection.at(1, 1), 1.0f, 1e-5f)
&& close_to(projection.at(2, 2), 1.1f, 1e-5f) && close_to(projection.at(2, 3), -1.1f, 1e-5f)
&& close_to(projection.at(3, 2), 1.0f, 1e-5f);
}(),
"Mat vertical-FOV perspective should be constexpr with gcem");
static_assert(
[]
{
constexpr auto projection =
mat_perspective_right_handed_horizontal_fov<float, MatStoreType::ROW_MAJOR,
NDCDepthRange::ZERO_TO_ONE>(90.0f, 2.0f, 1.0f, 11.0f);
return close_to(projection.at(0, 0), 1.0f, 1e-5f) && close_to(projection.at(1, 1), 2.0f, 1e-5f)
&& close_to(projection.at(2, 2), -1.1f, 1e-5f) && close_to(projection.at(2, 3), -1.1f, 1e-5f)
&& close_to(projection.at(3, 2), -1.0f, 1e-5f);
}(),
"Mat horizontal-FOV perspective should be constexpr with gcem");
#endif
+28
View File
@@ -8,6 +8,17 @@
using namespace omath; using namespace omath;
#ifdef OMATH_USE_GCEM
namespace
{
constexpr bool close_to(const float actual, const float expected, const float epsilon)
{
const float diff = actual - expected;
return (diff < 0.0f ? -diff : diff) <= epsilon;
}
} // namespace
#endif
class UnitTestTriangle : public ::testing::Test class UnitTestTriangle : public ::testing::Test
{ {
protected: protected:
@@ -129,3 +140,20 @@ TEST_F(UnitTestTriangle, MidPoint)
EXPECT_FLOAT_EQ(mid2.y, (2.0f + 5.0f + 8.0f) / 3.0f); EXPECT_FLOAT_EQ(mid2.y, (2.0f + 5.0f + 8.0f) / 3.0f);
EXPECT_FLOAT_EQ(mid2.z, (3.0f + 6.0f + 9.0f) / 3.0f); EXPECT_FLOAT_EQ(mid2.z, (3.0f + 6.0f + 9.0f) / 3.0f);
} }
#ifdef OMATH_USE_GCEM
static_assert(
[]
{
constexpr Triangle<Vector3<float>> triangle{{3.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 4.0f, 0.0f}};
constexpr auto normal = triangle.calculate_normal();
constexpr auto mid_point = triangle.mid_point();
return close_to(triangle.side_a_length(), 3.0f, 1e-5f) && close_to(triangle.side_b_length(), 4.0f, 1e-5f)
&& close_to(triangle.hypot(), 5.0f, 1e-5f) && triangle.is_rectangular()
&& close_to(normal.length(), 1.0f, 1e-5f) && close_to(normal.z, -1.0f, 1e-5f)
&& close_to(mid_point.x, 1.0f, 1e-5f) && close_to(mid_point.y, 4.0f / 3.0f, 1e-5f)
&& close_to(mid_point.z, 0.0f, 1e-5f);
}(),
"Triangle helpers should be constexpr with gcem");
#endif
+7 -2
View File
@@ -2,10 +2,10 @@
// Created by Vlad on 02.09.2024. // Created by Vlad on 02.09.2024.
// //
#include <omath/linear_algebra/vector2.hpp>
#include <cfloat> // For FLT_MAX and FLT_MIN #include <cfloat> // For FLT_MAX and FLT_MIN
#include <cmath> // For std::isinf and std::isnan #include <cmath> // For std::isinf and std::isnan
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <omath/linear_algebra/vector2.hpp>
using namespace omath; using namespace omath;
@@ -399,7 +399,6 @@ TEST_F(UnitTestVector2, GreaterEqualOperator)
EXPECT_TRUE(omath::Vector2(1.f, 1.f) >= omath::Vector2<float>{}); EXPECT_TRUE(omath::Vector2(1.f, 1.f) >= omath::Vector2<float>{});
} }
// ── Cast operator tests ────────────────────────────────────────────────────── // ── Cast operator tests ──────────────────────────────────────────────────────
TEST(Vector2Cast, FloatToDouble) TEST(Vector2Cast, FloatToDouble)
@@ -463,3 +462,9 @@ static_assert(Vector2(1.0f, 2.0f).length_sqr() == 5.0f, "LengthSqr should be 5")
static_assert(Vector2(1.0f, 2.0f).dot(Vector2(4.0f, 5.0f)) == 14.0f, "Dot product should be 14"); static_assert(Vector2(1.0f, 2.0f).dot(Vector2(4.0f, 5.0f)) == 14.0f, "Dot product should be 14");
static_assert(Vector2(4.0f, 5.0f).distance_to_sqr(Vector2(1.0f, 2.0f)) == 18.0f, "DistToSqr should be 18"); static_assert(Vector2(4.0f, 5.0f).distance_to_sqr(Vector2(1.0f, 2.0f)) == 18.0f, "DistToSqr should be 18");
static_assert(Vector2(-1.0f, -2.0f).abs() == Vector2(1.0f, 2.0f), "Abs should convert negative values to positive"); static_assert(Vector2(-1.0f, -2.0f).abs() == Vector2(1.0f, 2.0f), "Abs should convert negative values to positive");
#ifdef OMATH_USE_GCEM
static_assert(Vector2(3.0f, 4.0f).length() == 5.0f, "Length should be constexpr with gcem");
static_assert(Vector2(0.0f, 0.0f).distance_to(Vector2(3.0f, 4.0f)) == 5.0f, "Distance should be constexpr with gcem");
static_assert(Vector2(1.0f, 1.0f) < Vector2(3.0f, 4.0f), "Comparison should be constexpr with gcem");
#endif
+27 -16
View File
@@ -2,11 +2,11 @@
// Created by Vlad on 01.09.2024. // Created by Vlad on 01.09.2024.
// //
#include <omath/linear_algebra/vector3.hpp>
#include <cfloat> // For FLT_MAX, FLT_MIN #include <cfloat> // For FLT_MAX, FLT_MIN
#include <cmath> #include <cmath>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <limits> // For std::numeric_limits #include <limits> // For std::numeric_limits
#include <omath/linear_algebra/vector3.hpp>
using namespace omath; using namespace omath;
@@ -31,35 +31,33 @@ TEST(Vector3More, ArithmeticAndDotCross)
constexpr Vector3<float> a{1.f, 0.f, 0.f}; constexpr Vector3<float> a{1.f, 0.f, 0.f};
constexpr Vector3<float> b{0.f, 1.f, 0.f}; constexpr Vector3<float> b{0.f, 1.f, 0.f};
const auto c = a + b; const auto c = a + b;
constexpr Vector3<float> expect_c{1.f,1.f,0.f}; constexpr Vector3<float> expect_c{1.f, 1.f, 0.f};
EXPECT_EQ(c, expect_c); EXPECT_EQ(c, expect_c);
const auto d = a - b; const auto d = a - b;
constexpr Vector3<float> expect_d{1.f,-1.f,0.f}; constexpr Vector3<float> expect_d{1.f, -1.f, 0.f};
EXPECT_EQ(d, expect_d); EXPECT_EQ(d, expect_d);
const auto e = a * 2.f; const auto e = a * 2.f;
constexpr Vector3<float> expect_e{2.f,0.f,0.f}; constexpr Vector3<float> expect_e{2.f, 0.f, 0.f};
EXPECT_EQ(e, expect_e); EXPECT_EQ(e, expect_e);
EXPECT_FLOAT_EQ(a.dot(b), 0.f); EXPECT_FLOAT_EQ(a.dot(b), 0.f);
// manual cross product check // manual cross product check
const auto cr = Vector3<float>{ a.y * b.z - a.z * b.y, const auto cr = Vector3<float>{a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
a.z * b.x - a.x * b.z, constexpr Vector3<float> expect_cr{0.f, 0.f, 1.f};
a.x * b.y - a.y * b.x };
constexpr Vector3<float> expect_cr{0.f,0.f,1.f};
EXPECT_EQ(cr, expect_cr); EXPECT_EQ(cr, expect_cr);
} }
TEST(Vector3More, NormalizationEdgeCases) TEST(Vector3More, NormalizationEdgeCases)
{ {
constexpr Vector3<double> z{0.0,0.0,0.0}; constexpr Vector3<double> z{0.0, 0.0, 0.0};
const auto zn = z.normalized(); const auto zn = z.normalized();
EXPECT_DOUBLE_EQ(zn.x, 0.0); EXPECT_DOUBLE_EQ(zn.x, 0.0);
EXPECT_DOUBLE_EQ(zn.y, 0.0); EXPECT_DOUBLE_EQ(zn.y, 0.0);
EXPECT_DOUBLE_EQ(zn.z, 0.0); EXPECT_DOUBLE_EQ(zn.z, 0.0);
constexpr Vector3<double> v{3.0,4.0,0.0}; constexpr Vector3<double> v{3.0, 4.0, 0.0};
const auto vn = v.normalized(); const auto vn = v.normalized();
EXPECT_NEAR(vn.x, 0.6, 1e-12); EXPECT_NEAR(vn.x, 0.6, 1e-12);
EXPECT_NEAR(vn.y, 0.8, 1e-12); EXPECT_NEAR(vn.y, 0.8, 1e-12);
@@ -481,16 +479,14 @@ TEST_F(UnitTestVector3, AsTuple)
// Test AsTuple method // Test AsTuple method
TEST_F(UnitTestVector3, AngleBeatween) TEST_F(UnitTestVector3, AngleBeatween)
{ {
EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({1, 0, 0}).value().as_degrees(), EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({1, 0, 0}).value().as_degrees(), 90.0f, 0.001f);
90.0f, 0.001f); EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({0.0f, 0.0f, 1.0f}).value().as_degrees(), 0.0f, 0.001f);
EXPECT_NEAR(Vector3(0.0f, 0.0f, 1.0f).angle_between({0.0f, 0.0f, 1.0f}).value().as_degrees(),
0.0f, 0.001f);
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).angle_between({0.0f, 0.0f, 1.0f}).has_value()); EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).angle_between({0.0f, 0.0f, 1.0f}).has_value());
} }
TEST_F(UnitTestVector3, IsPerpendicular) TEST_F(UnitTestVector3, IsPerpendicular)
{ {
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({1, 0 ,0}), true); EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({1, 0, 0}), true);
EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({0.0f, 0.0f, 1.0f}), false); EXPECT_EQ(Vector3(0.0f, 0.0f, 1.0f).is_perpendicular({0.0f, 0.0f, 1.0f}), false);
EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).is_perpendicular({0.0f, 0.0f, 1.0f})); EXPECT_FALSE(Vector3(0.0f, 0.0f, 0.0f).is_perpendicular({0.0f, 0.0f, 1.0f}));
} }
@@ -585,4 +581,19 @@ TEST(Vector3Cast, SameTypeRoundtrip)
static_assert(Vector3(1.0f, 2.0f, 3.0f).length_sqr() == 14.0f, "LengthSqr should be 14"); static_assert(Vector3(1.0f, 2.0f, 3.0f).length_sqr() == 14.0f, "LengthSqr should be 14");
static_assert(Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f)) == 32.0f, "Dot product should be 32"); static_assert(Vector3(1.0f, 2.0f, 3.0f).dot(Vector3(4.0f, 5.0f, 6.0f)) == 32.0f, "Dot product should be 32");
static_assert(Vector3(4.0f, 5.0f, 6.0f).distance_to_sqr(Vector3(1.0f, 2.0f, 3.0f)) == 27.0f, "DistToSqr should be 27"); static_assert(Vector3(4.0f, 5.0f, 6.0f).distance_to_sqr(Vector3(1.0f, 2.0f, 3.0f)) == 27.0f, "DistToSqr should be 27");
static_assert(Vector3(-1.0f, -2.0f, -3.0f).abs() == Vector3(1.0f, 2.0f, 3.0f), "Abs should convert negative values to positive"); static_assert(Vector3(-1.0f, -2.0f, -3.0f).abs() == Vector3(1.0f, 2.0f, 3.0f),
"Abs should convert negative values to positive");
#ifdef OMATH_USE_GCEM
static_assert(Vector3(1.0f, 2.0f, 2.0f).length() == 3.0f, "Length should be constexpr with gcem");
static_assert(Vector3(0.0f, 0.0f, 0.0f).distance_to(Vector3(1.0f, 2.0f, 2.0f)) == 3.0f,
"Distance should be constexpr with gcem");
static_assert(Vector3(1.0f, 1.0f, 1.0f) < Vector3(3.0f, 4.0f, 5.0f), "Comparison should be constexpr with gcem");
static_assert(
[]
{
constexpr auto angle = Vector3(1.0f, 0.0f, 0.0f).angle_between(Vector3(0.0f, 1.0f, 0.0f));
return angle.has_value() && angle->as_degrees() > 89.999f && angle->as_degrees() < 90.001f;
}(),
"Angle between should be constexpr with gcem");
#endif
+7
View File
@@ -82,6 +82,13 @@
"lua", "lua",
"sol2" "sol2"
] ]
},
"gcem":
{
"description": "Improve constexpr compatibility using gcem",
"dependencies": [
"gcem"
]
} }
} }
} }