diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a465d7..3f5b1df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ option(SMATH_BUILD_EXAMPLES "Build example programs" ON) option(SMATH_BUILD_TESTS "Build unit tests" ON) option(SMATH_BUILD_MODULES "Enable C++20 modules support" OFF) option(SMATH_ENABLE_LEGACY_HEADER "Install legacy include shim" OFF) +option(SMATH_INSTALL_INTEROP_HEADERS "Install interop headers" OFF) if(SMATH_BUILD_MODULES) message(STATUS "Building smath C++ module") @@ -27,7 +28,11 @@ include(CMakePackageConfigHelpers) install(TARGETS smath EXPORT smathTargets ) -install(DIRECTORY include/ DESTINATION include) +install(FILES include/smath/smath.hpp DESTINATION include/smath) + +if(SMATH_INSTALL_INTEROP_HEADERS) + install(DIRECTORY include/smath/interop DESTINATION include/smath) +endif() if(SMATH_ENABLE_LEGACY_HEADER) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include") diff --git a/README.md b/README.md index f100e40..3a06797 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,26 @@

+## Features + +- Generic `Vec` class with useful aliases `Vec2/Vec3/Vec4` and friendly accessors (`x/y/z/w`, `r/g/b/a`). They support approx-equal and tuple/structured bindings. +- `std::format` support. +- Compile-time swizzles via `swizzle<"...">`. +- Generic matrix `Mat` class with useful aliases `Mat2/Mat3/Mat4`. +- `Quaternion` built on `Vec4`. +- Angle helpers `rad/deg/turns` respecting a configurable base unit via the macro `SMATH_ANGLE_UNIT`. +- Optional implicit conversions. +- Packing utilities for normalized RGBA (`pack_unorm4x8`, `unpack_snorm4x8`, etc.). +- C++20 modules support. +- Built-in interop adapter and optional interop headers for various libraries. + ## Quick Start Create `main.cpp`: ```cpp #include -#include +#include int main() { using namespace smath; @@ -39,17 +52,20 @@ g++ -std=c++23 -Iinclude main.cpp -o quickstart ./quickstart ``` -## Features +## Interop Headers -- Generic `Vec` class with useful aliases `Vec2/Vec3/Vec4` and friendly accessors (`x/y/z/w`, `r/g/b/a`). They support approx-equal and tuple/structured bindings. -- `std::format` support. -- Compile-time swizzles via `swizzle<"...">`. -- Generic matrix `Mat` class with useful aliases `Mat2/Mat3/Mat4`. -- `Quaternion` built on `Vec4`. -- Angle helpers `rad/deg/turns` respecting a configurable base unit via the macro `SMATH_ANGLE_UNIT`. -- Optional implicit conversions. -- Packing utilities for normalized RGBA (`pack_unorm4x8`, `unpack_snorm4x8`, etc.). -- C++20 modules support. +smath ships optional interop adapters under `include/smath/interop/`. + +When installing with CMake, interop headers are gated behind: + +- `-DSMATH_INSTALL_INTEROP_HEADERS=ON` + +All of them plug into the same generic API defined in `smath.hpp`: + +```cpp +auto v = smath::from_external(external_value); +auto ext = smath::to_external(smath_value); +``` ## License diff --git a/flake.nix b/flake.nix index 40d9f94..a0c960f 100644 --- a/flake.nix +++ b/flake.nix @@ -55,10 +55,14 @@ }) ]; + extraCMakeFlags = [ + "-DSMATH_INSTALL_INTEROP_HEADERS=ON" + ]; + installPhase = '' runHook preInstall - mkdir -p $out/include/smath - cp ../include/smath/smath.hpp $out/include/smath/ + mkdir -p $out/include/ + cp -r ../include/smath/ $out/include/ runHook postInstall ''; diff --git a/include/smath/interop/eigen.hpp b/include/smath/interop/eigen.hpp new file mode 100644 index 0000000..a904706 --- /dev/null +++ b/include/smath/interop/eigen.hpp @@ -0,0 +1,131 @@ +/* + * smath - Single-file linear algebra math library for C++23. + * + * Copyright 2025 Slendi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace smath +{ + +template +requires(std::is_arithmetic_v && (N > 0)) +struct interop_adapter> +{ + using smath_type = Vec(N), Scalar>; + + static constexpr auto to_smath( + Eigen::Matrix const &v) + -> smath_type + { + smath_type out {}; + for (std::size_t i = 0; i < static_cast(N); ++i) + out[i] = v(static_cast(i)); + return out; + } + + static constexpr auto from_smath(smath_type const &v) + -> Eigen::Matrix + { + Eigen::Matrix out; + for (std::size_t i = 0; i < static_cast(N); ++i) + out(static_cast(i)) = v[i]; + return out; + } +}; + +template +requires(std::is_arithmetic_v && (N > 0)) +struct interop_adapter> +{ + using smath_type = Vec(N), Scalar>; + + static constexpr auto to_smath( + Eigen::Matrix const &v) + -> smath_type + { + smath_type out {}; + for (std::size_t i = 0; i < static_cast(N); ++i) + out[i] = v(static_cast(i)); + return out; + } + + static constexpr auto from_smath(smath_type const &v) + -> Eigen::Matrix + { + Eigen::Matrix out; + for (std::size_t i = 0; i < static_cast(N); ++i) + out(static_cast(i)) = v[i]; + return out; + } +}; + +template +requires(std::is_arithmetic_v && (R > 1) && (C > 1)) +struct interop_adapter> +{ + using smath_type + = Mat(R), static_cast(C), Scalar>; + + static constexpr auto to_smath( + Eigen::Matrix const &m) + -> smath_type + { + smath_type out {}; + for (std::size_t c = 0; c < static_cast(C); ++c) { + for (std::size_t r = 0; r < static_cast(R); ++r) + out[r, c] = m(static_cast(r), static_cast(c)); + } + return out; + } + + static constexpr auto from_smath(smath_type const &m) + -> Eigen::Matrix + { + Eigen::Matrix out; + for (std::size_t c = 0; c < static_cast(C); ++c) { + for (std::size_t r = 0; r < static_cast(R); ++r) + out(static_cast(r), static_cast(c)) = m[r, c]; + } + return out; + } +}; + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type = Quaternion; + + static constexpr auto to_smath(Eigen::Quaternion const &q) + -> smath_type + { + return { q.x(), q.y(), q.z(), q.w() }; + } + + static constexpr auto from_smath(smath_type const &q) + -> Eigen::Quaternion + { + return { q.w(), q.x(), q.y(), q.z() }; + } +}; + +} // namespace smath diff --git a/include/smath/interop/glm.hpp b/include/smath/interop/glm.hpp new file mode 100644 index 0000000..b9558bb --- /dev/null +++ b/include/smath/interop/glm.hpp @@ -0,0 +1,103 @@ +/* + * smath - Single-file linear algebra math library for C++23. + * + * Copyright 2025 Slendi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace smath +{ + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type = Vec(L), T>; + + static constexpr auto to_smath(glm::vec const &v) -> smath_type + { + smath_type out {}; + for (std::size_t i = 0; i < static_cast(L); ++i) + out[i] = v[static_cast(i)]; + return out; + } + + static constexpr auto from_smath(smath_type const &v) -> glm::vec + { + glm::vec out {}; + for (std::size_t i = 0; i < static_cast(L); ++i) + out[static_cast(i)] = v[i]; + return out; + } +}; + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type + = Mat(R), static_cast(C), T>; + + static constexpr auto to_smath(glm::mat const &m) -> smath_type + { + smath_type out {}; + for (std::size_t c = 0; c < static_cast(C); ++c) { + for (std::size_t r = 0; r < static_cast(R); ++r) { + out[r, c] = m[static_cast(c)] + [static_cast(r)]; + } + } + return out; + } + + static constexpr auto from_smath(smath_type const &m) + -> glm::mat + { + glm::mat out {}; + for (std::size_t c = 0; c < static_cast(C); ++c) { + for (std::size_t r = 0; r < static_cast(R); ++r) { + out[static_cast(c)] + [static_cast(r)] + = m[r, c]; + } + } + return out; + } +}; + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type = Quaternion; + + static constexpr auto to_smath(glm::qua const &q) -> smath_type + { + return { q.x, q.y, q.z, q.w }; + } + + static constexpr auto from_smath(smath_type const &q) -> glm::qua + { + return { q.w(), q.x(), q.y(), q.z() }; + } +}; + +} // namespace smath diff --git a/include/smath/interop/hmm.hpp b/include/smath/interop/hmm.hpp new file mode 100644 index 0000000..f1b920e --- /dev/null +++ b/include/smath/interop/hmm.hpp @@ -0,0 +1,125 @@ +/* + * smath - Single-file linear algebra math library for C++23. + * + * Copyright 2025 Slendi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace smath +{ + +template<> struct interop_adapter +{ + using smath_type = Vec<2, float>; + + static constexpr auto to_smath(HMM_Vec2 const &v) -> smath_type + { + return { v.X, v.Y }; + } + + static constexpr auto from_smath(smath_type const &v) -> HMM_Vec2 + { + return { v.x(), v.y() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Vec<3, float>; + + static constexpr auto to_smath(HMM_Vec3 const &v) -> smath_type + { + return { v.X, v.Y, v.Z }; + } + + static constexpr auto from_smath(smath_type const &v) -> HMM_Vec3 + { + return { v.x(), v.y(), v.z() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Vec<4, float>; + + static constexpr auto to_smath(HMM_Vec4 const &v) -> smath_type + { + return { v.X, v.Y, v.Z, v.W }; + } + + static constexpr auto from_smath(smath_type const &v) -> HMM_Vec4 + { + return { v.x(), v.y(), v.z(), v.w() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Mat<4, 4, float>; + + static constexpr auto to_smath(HMM_Mat4 const &m) -> smath_type + { + smath_type out {}; + out[0, 0] = m.Columns[0].X; + out[1, 0] = m.Columns[0].Y; + out[2, 0] = m.Columns[0].Z; + out[3, 0] = m.Columns[0].W; + out[0, 1] = m.Columns[1].X; + out[1, 1] = m.Columns[1].Y; + out[2, 1] = m.Columns[1].Z; + out[3, 1] = m.Columns[1].W; + out[0, 2] = m.Columns[2].X; + out[1, 2] = m.Columns[2].Y; + out[2, 2] = m.Columns[2].Z; + out[3, 2] = m.Columns[2].W; + out[0, 3] = m.Columns[3].X; + out[1, 3] = m.Columns[3].Y; + out[2, 3] = m.Columns[3].Z; + out[3, 3] = m.Columns[3].W; + return out; + } + + static constexpr auto from_smath(smath_type const &m) -> HMM_Mat4 + { + HMM_Mat4 out {}; + out.Columns[0] = { m[0, 0], m[1, 0], m[2, 0], m[3, 0] }; + out.Columns[1] = { m[0, 1], m[1, 1], m[2, 1], m[3, 1] }; + out.Columns[2] = { m[0, 2], m[1, 2], m[2, 2], m[3, 2] }; + out.Columns[3] = { m[0, 3], m[1, 3], m[2, 3], m[3, 3] }; + return out; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Quaternion; + + static constexpr auto to_smath(HMM_Quat const &q) -> smath_type + { + return { q.X, q.Y, q.Z, q.W }; + } + + static constexpr auto from_smath(smath_type const &q) -> HMM_Quat + { + return { q.x(), q.y(), q.z(), q.w() }; + } +}; + +} // namespace smath diff --git a/include/smath/interop/raylib.hpp b/include/smath/interop/raylib.hpp new file mode 100644 index 0000000..27c78c5 --- /dev/null +++ b/include/smath/interop/raylib.hpp @@ -0,0 +1,122 @@ +/* + * smath - Single-file linear algebra math library for C++23. + * + * Copyright 2025 Slendi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace smath +{ + +template<> struct interop_adapter +{ + using smath_type = Vec<2, float>; + + static constexpr auto to_smath(Vector2 const &v) -> smath_type + { + return { v.x, v.y }; + } + + static constexpr auto from_smath(smath_type const &v) -> Vector2 + { + return { v.x(), v.y() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Vec<3, float>; + + static constexpr auto to_smath(Vector3 const &v) -> smath_type + { + return { v.x, v.y, v.z }; + } + + static constexpr auto from_smath(smath_type const &v) -> Vector3 + { + return { v.x(), v.y(), v.z() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Vec<4, float>; + + static constexpr auto to_smath(Vector4 const &v) -> smath_type + { + return { v.x, v.y, v.z, v.w }; + } + + static constexpr auto from_smath(smath_type const &v) -> Vector4 + { + return { v.x(), v.y(), v.z(), v.w() }; + } +}; + +template<> struct interop_adapter +{ + using smath_type = Mat<4, 4, float>; + + static constexpr auto to_smath(Matrix const &m) -> smath_type + { + smath_type out {}; + out[0, 0] = m.m0; + out[1, 0] = m.m1; + out[2, 0] = m.m2; + out[3, 0] = m.m3; + out[0, 1] = m.m4; + out[1, 1] = m.m5; + out[2, 1] = m.m6; + out[3, 1] = m.m7; + out[0, 2] = m.m8; + out[1, 2] = m.m9; + out[2, 2] = m.m10; + out[3, 2] = m.m11; + out[0, 3] = m.m12; + out[1, 3] = m.m13; + out[2, 3] = m.m14; + out[3, 3] = m.m15; + return out; + } + + static constexpr auto from_smath(smath_type const &m) -> Matrix + { + return { + m[0, 0], + m[0, 1], + m[0, 2], + m[0, 3], + m[1, 0], + m[1, 1], + m[1, 2], + m[1, 3], + m[2, 0], + m[2, 1], + m[2, 2], + m[2, 3], + m[3, 0], + m[3, 1], + m[3, 2], + m[3, 3], + }; + } +}; + +} // namespace smath diff --git a/include/smath/interop/sfml.hpp b/include/smath/interop/sfml.hpp new file mode 100644 index 0000000..a0f95dc --- /dev/null +++ b/include/smath/interop/sfml.hpp @@ -0,0 +1,63 @@ +/* + * smath - Single-file linear algebra math library for C++23. + * + * Copyright 2025 Slendi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace smath +{ + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type = Vec<2, T>; + + static constexpr auto to_smath(sf::Vector2 const &v) -> smath_type + { + return { v.x, v.y }; + } + + static constexpr auto from_smath(smath_type const &v) -> sf::Vector2 + { + return { v.x(), v.y() }; + } +}; + +template +requires std::is_arithmetic_v +struct interop_adapter> +{ + using smath_type = Vec<3, T>; + + static constexpr auto to_smath(sf::Vector3 const &v) -> smath_type + { + return { v.x, v.y, v.z }; + } + + static constexpr auto from_smath(smath_type const &v) -> sf::Vector3 + { + return { v.x(), v.y(), v.z() }; + } +}; + +} // namespace smath