diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index dde5e96..3e1f0d2 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -37,7 +37,7 @@ jobs: - name: Set up vcpkg shell: bash run: | - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" - name: Configure (cmake --preset) shell: bash run: cmake --preset linux-release-vcpkg -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests" @@ -53,7 +53,7 @@ jobs: ############################################################################## - # 2) Windows – MSVC / Ninja + # 2) Windows x64 – MSVC (x64-windows) ############################################################################## windows-build-and-test: name: Windows (MSVC) (x64-windows) @@ -85,6 +85,43 @@ jobs: shell: bash run: ./out/Release/unit_tests.exe + + + ############################################################################## + # 3) Windows x86 – MSVC (x86-windows) + ############################################################################## + windows-x86-build-and-test: + name: Windows (MSVC) (x86-windows) + runs-on: windows-latest + env: + OMATH_BUILD_VIA_VCPKG: ON + + steps: + - name: Checkout repository (with sub-modules) + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@v4 + + - name: Set up MSVC developer command-prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_x86 + + - name: Configure (cmake --preset) + shell: bash + run: cmake --preset windows-release-vcpkg-x86 -DOMATH_BUILD_TESTS=ON -DOMATH_BUILD_BENCHMARK=OFF -DVCPKG_MANIFEST_FEATURES="imgui;avx2;tests" + + - name: Build + shell: bash + run: cmake --build cmake-build/build/windows-release-vcpkg-x86 --target unit_tests omath + + - name: Run unit_tests.exe + shell: bash + run: ./out/Release/unit_tests.exe + ############################################################################## # 3) macOS – AppleClang / Ninja ############################################################################## @@ -107,7 +144,7 @@ jobs: - name: Set up vcpkg shell: bash run: | - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" - name: Configure (cmake --preset) shell: bash @@ -143,7 +180,7 @@ jobs: - name: Set up vcpkg shell: bash run: | - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" cd "$VCPKG_ROOT" ./bootstrap-vcpkg.sh @@ -187,7 +224,7 @@ jobs: # This prevents PCH timestamp mismatches during parallel builds export VCPKG_ROOT=/tmp/vcpkg rm -rf "$VCPKG_ROOT" - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" cd "$VCPKG_ROOT" # Bootstrap vcpkg - it will build from source on FreeBSD # Building in /tmp avoids sshfs timestamp issues that break PCH @@ -236,7 +273,7 @@ jobs: - name: Set up vcpkg shell: bash run: | - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" cd "$VCPKG_ROOT" ./bootstrap-vcpkg.sh @@ -290,7 +327,7 @@ jobs: - name: Set up vcpkg shell: bash run: | - git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" cd "$VCPKG_ROOT" ./bootstrap-vcpkg.sh @@ -306,4 +343,169 @@ jobs: - name: Build shell: bash run: | - cmake --build cmake-build/build/wasm-release-vcpkg --target unit_tests omath \ No newline at end of file + cmake --build cmake-build/build/wasm-release-vcpkg --target unit_tests omath + + ############################################################################## + # 7) Windows MSYS2 MinGW – GCC / Ninja / x64-mingw-dynamic + ############################################################################## + mingw-build-and-test: + name: MINGW64 (MSYS2) (x64-mingw-dynamic) + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + env: + VCPKG_ROOT: ${{ github.workspace }}/vcpkg + + steps: + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-ninja + mingw-w64-x86_64-pkg-config + git + base-devel + + - name: Checkout repository (with sub-modules) + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up vcpkg + run: | + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + cd "$VCPKG_ROOT" + ./bootstrap-vcpkg.sh + + - name: Configure (cmake --preset) + run: | + cmake --preset mingw-release-vcpkg \ + -DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \ + -DOMATH_BUILD_TESTS=ON \ + -DOMATH_BUILD_BENCHMARK=OFF \ + -DVCPKG_MANIFEST_FEATURES="imgui;tests" + + - name: Build + run: | + cmake --build cmake-build/build/mingw-release-vcpkg --target unit_tests omath + + - name: Run unit_tests.exe + run: | + ./out/Release/unit_tests.exe + + ############################################################################## + # 8) Windows UCRT64 MSYS2 MinGW – GCC / Ninja / x64-mingw-dynamic + ############################################################################## + mingw-ucrt-build-and-test: + name: UCRT64 (MSYS2) (x64-mingw-dynamic) + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + env: + VCPKG_ROOT: ${{ github.workspace }}/vcpkg + + steps: + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: >- + mingw-w64-ucrt-x86_64-toolchain + mingw-w64-ucrt-x86_64-cmake + mingw-w64-ucrt-x86_64-ninja + mingw-w64-ucrt-x86_64-pkg-config + git + base-devel + + - name: Checkout repository (with sub-modules) + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up vcpkg + run: | + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + cd "$VCPKG_ROOT" + ./bootstrap-vcpkg.sh + + - name: Configure (cmake --preset) + run: | + cmake --preset mingw-release-vcpkg \ + -DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \ + -DOMATH_BUILD_TESTS=ON \ + -DOMATH_BUILD_BENCHMARK=OFF \ + -DVCPKG_MANIFEST_FEATURES="imgui;tests" + + - name: Build + run: | + cmake --build cmake-build/build/mingw-release-vcpkg --target unit_tests omath + + - name: Run unit_tests.exe + run: | + ./out/Release/unit_tests.exe + + ############################################################################## + # 9) Windows MSYS2 MinGW32 – GCC / Ninja / x86-mingw-dynamic + ############################################################################## + mingw32-build-and-test: + name: MINGW32 (MSYS2) (x86-mingw-dynamic) + runs-on: windows-latest + + defaults: + run: + shell: msys2 {0} + + env: + VCPKG_ROOT: ${{ github.workspace }}/vcpkg + + steps: + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW32 + update: true + install: >- + mingw-w64-i686-toolchain + mingw-w64-i686-cmake + mingw-w64-i686-ninja + mingw-w64-i686-pkg-config + git + base-devel + + - name: Checkout repository (with sub-modules) + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up vcpkg + run: | + git clone --branch 2025.12.12 --single-branch https://github.com/microsoft/vcpkg "$VCPKG_ROOT" + cd "$VCPKG_ROOT" + ./bootstrap-vcpkg.sh + + - name: Configure (cmake --preset) + run: | + cmake --preset mingw32-release-vcpkg \ + -DVCPKG_INSTALL_OPTIONS="--allow-unsupported" \ + -DOMATH_BUILD_TESTS=ON \ + -DOMATH_BUILD_BENCHMARK=OFF \ + -DVCPKG_MANIFEST_FEATURES="imgui;tests" + + - name: Build + run: | + cmake --build cmake-build/build/mingw32-release-vcpkg --target unit_tests omath + + - name: Run unit_tests.exe + run: | + ./out/Release/unit_tests.exe diff --git a/CMakePresets.json b/CMakePresets.json index 7f14cbc..bc74347 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -53,6 +53,40 @@ "OMATH_BUILD_VIA_VCPKG": "ON" } }, + { + "name": "windows-base-vcpkg-x86", + "hidden": true, + "inherits": "windows-base", + "architecture": { + "value": "x86", + "strategy": "external" + }, + "cacheVariables": { + "OMATH_BUILD_VIA_VCPKG": "ON", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed", + "VCPKG_TARGET_TRIPLET": "x86-windows", + "VCPKG_HOST_TRIPLET": "x64-windows", + "VCPKG_MANIFEST_FEATURES": "tests;imgui;avx2;examples" + } + }, + { + "name": "windows-debug-vcpkg-x86", + "displayName": "Windows Debug Vcpkg (x86)", + "inherits": "windows-base-vcpkg-x86", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "windows-release-vcpkg-x86", + "displayName": "Windows Release Vcpkg (x86)", + "inherits": "windows-base-vcpkg-x86", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "OMATH_BUILD_VIA_VCPKG": "ON" + } + }, { "name": "windows-release", "displayName": "Release", @@ -365,6 +399,160 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } + }, + { + "name": "mingw-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/cmake-build/build/${presetName}", + "installDir": "${sourceDir}/cmake-build/install/${presetName}", + "cacheVariables": { + "CMAKE_CXX_COMPILER": "g++", + "CMAKE_C_COMPILER": "gcc", + "CMAKE_MAKE_PROGRAM": "ninja" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw-ucrt-base-vcpkg", + "hidden": true, + "inherits": "mingw-base", + "environment": { + "VCPKG_DEFAULT_HOST_TRIPLET": "x64-mingw-dynamic" + }, + "cacheVariables": { + "OMATH_BUILD_VIA_VCPKG": "ON", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed", + "VCPKG_TARGET_TRIPLET": "x64-mingw-dynamic", + "VCPKG_HOST_TRIPLET": "x64-mingw-dynamic", + "VCPKG_MANIFEST_FEATURES": "tests;imgui" + } + }, + { + "name": "mingw-ucrt-release-vcpkg", + "displayName": "MinGW UCRT64 Release Vcpkg", + "inherits": "mingw-ucrt-base-vcpkg", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "mingw-base-vcpkg", + "hidden": true, + "inherits": "mingw-base", + "environment": { + "VCPKG_DEFAULT_HOST_TRIPLET": "x64-mingw-dynamic" + }, + "cacheVariables": { + "OMATH_BUILD_VIA_VCPKG": "ON", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed", + "VCPKG_TARGET_TRIPLET": "x64-mingw-dynamic", + "VCPKG_HOST_TRIPLET": "x64-mingw-dynamic", + "VCPKG_MANIFEST_FEATURES": "tests;imgui" + } + }, + { + "name": "mingw-debug", + "displayName": "MinGW Debug", + "inherits": "mingw-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "mingw-debug-vcpkg", + "displayName": "MinGW Debug Vcpkg", + "inherits": "mingw-base-vcpkg", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "mingw-release", + "displayName": "MinGW Release", + "inherits": "mingw-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "mingw-release-vcpkg", + "displayName": "MinGW Release Vcpkg", + "inherits": "mingw-base-vcpkg", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "mingw32-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/cmake-build/build/${presetName}", + "installDir": "${sourceDir}/cmake-build/install/${presetName}", + "cacheVariables": { + "CMAKE_CXX_COMPILER": "g++", + "CMAKE_C_COMPILER": "gcc", + "CMAKE_MAKE_PROGRAM": "ninja" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw32-base-vcpkg", + "hidden": true, + "inherits": "mingw32-base", + "environment": { + "VCPKG_DEFAULT_HOST_TRIPLET": "x86-mingw-dynamic" + }, + "cacheVariables": { + "OMATH_BUILD_VIA_VCPKG": "ON", + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_INSTALLED_DIR": "${sourceDir}/cmake-build/vcpkg_installed", + "VCPKG_TARGET_TRIPLET": "x86-mingw-dynamic", + "VCPKG_HOST_TRIPLET": "x86-mingw-dynamic", + "VCPKG_MANIFEST_FEATURES": "tests;imgui" + } + }, + { + "name": "mingw32-debug", + "displayName": "MinGW32 Debug", + "inherits": "mingw32-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "mingw32-debug-vcpkg", + "displayName": "MinGW32 Debug Vcpkg", + "inherits": "mingw32-base-vcpkg", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "mingw32-release", + "displayName": "MinGW32 Release", + "inherits": "mingw32-base", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "mingw32-release-vcpkg", + "displayName": "MinGW32 Release Vcpkg", + "inherits": "mingw32-base-vcpkg", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } } ] } \ No newline at end of file diff --git a/include/omath/linear_algebra/mat.hpp b/include/omath/linear_algebra/mat.hpp index e86a57f..f0a7aa4 100644 --- a/include/omath/linear_algebra/mat.hpp +++ b/include/omath/linear_algebra/mat.hpp @@ -380,7 +380,7 @@ namespace omath { const auto det = determinant(); - if (det == 0) + if (std::abs(det) < std::numeric_limits::epsilon()) return std::nullopt; const auto transposed_mat = transposed(); diff --git a/include/omath/projection/camera.hpp b/include/omath/projection/camera.hpp index 291f189..37a3ef8 100644 --- a/include/omath/projection/camera.hpp +++ b/include/omath/projection/camera.hpp @@ -8,6 +8,7 @@ #include "omath/linear_algebra/triangle.hpp" #include "omath/linear_algebra/vector3.hpp" #include "omath/projection/error_codes.hpp" +#include #include #include #include @@ -229,10 +230,11 @@ namespace omath::projection auto projected = get_view_projection_matrix() * mat_column_from_vector(world_position); - if (projected.at(3, 0) == 0.0f) + const auto& w = projected.at(3, 0); + if (w <= std::numeric_limits::epsilon()) return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); - projected /= projected.at(3, 0); + projected /= w; if (is_ndc_out_of_bounds(projected)) return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); @@ -250,10 +252,12 @@ namespace omath::projection auto inverted_projection = inv_view_proj.value() * mat_column_from_vector(ndc); - if (!inverted_projection.at(3, 0)) + const auto& w = inverted_projection.at(3, 0); + + if (std::abs(w) < std::numeric_limits::epsilon()) return std::unexpected(Error::WORLD_POSITION_IS_OUT_OF_SCREEN_BOUNDS); - inverted_projection /= inverted_projection.at(3, 0); + inverted_projection /= w; return Vector3{inverted_projection.at(0, 0), inverted_projection.at(1, 0), inverted_projection.at(2, 0)}; @@ -290,7 +294,9 @@ namespace omath::projection template [[nodiscard]] constexpr static bool is_ndc_out_of_bounds(const Type& ndc) noexcept { - return std::ranges::any_of(ndc.raw_array(), [](const auto& val) { return val < -1 || val > 1; }); + constexpr auto eps = std::numeric_limits::epsilon(); + return std::ranges::any_of(ndc.raw_array(), + [](const auto& val) { return val < -1.0f - eps || val > 1.0f + eps; }); } // NDC REPRESENTATION: @@ -347,7 +353,7 @@ namespace omath::projection if constexpr (screen_start == ScreenStart::TOP_LEFT_CORNER) return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, 1.f - screen_pos.y / m_view_port.m_height * 2.f, screen_pos.z}; - else if (screen_start == ScreenStart::BOTTOM_LEFT_CORNER) + else if constexpr (screen_start == ScreenStart::BOTTOM_LEFT_CORNER) return {screen_pos.x / m_view_port.m_width * 2.f - 1.f, (screen_pos.y / m_view_port.m_height - 0.5f) * 2.f, screen_pos.z}; else diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fd42c15..1502fcf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,7 +23,7 @@ else() # GTest is being linked as vcpkg package target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest GTest::gtest_main omath::omath) endif() -# Skip test discovery for Android builds - binaries cannot run on host -if (NOT (CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "iOS")) +# Skip test discovery for Android/iOS builds or when cross-compiling - binaries cannot run on host +if (NOT (ANDROID OR IOS)) gtest_discover_tests(${PROJECT_NAME}) endif()