No description
  • C++ 94.7%
  • CMake 5.3%
Find a file
2026-06-20 13:43:09 +02:00
cmake adds install config file 2026-02-15 20:22:36 +01:00
src/sgl add common type for segment closest result 2026-05-30 18:14:50 +02:00
tests disable pedantic cppcore warnings in clang-tidy file 2026-05-30 18:15:57 +02:00
.clang-format add pre commit and related files 2026-05-30 14:17:33 +02:00
.clang-tidy disable pedantic cppcore warnings in clang-tidy file 2026-05-30 18:15:57 +02:00
.cmake-format.yaml add pre commit and related files 2026-05-30 14:17:33 +02:00
.gitignore adds git ignore 2026-02-15 19:41:12 +01:00
.pre-commit-config.yaml add pre commit and related files 2026-05-30 14:17:33 +02:00
CMakeLists.txt move test root in cmake file 2026-05-30 18:16:56 +02:00
LICENSE add MIT license 2026-05-30 18:25:11 +02:00
README.md improvements to README 2026-06-20 13:43:09 +02:00

sgl

A C++20 module-based, SIMD-accelerated computational geometry library.

sgl is a SIMD-first library for fixed-size linear algebra and geometry: vectors, matrices, quaternions, axis-aligned boxes, planes, transforms, and the intersection and distance queries built on them. Every operation is written directly against SSE/AVX2 or NEON intrinsics, and C++20 templates collapse the per-type and per-dimension boilerplate, so the API surface stays broad while the implementation stays compact. It covers the everyday graphics and geometry math, and is at its strongest in the spatial queries that run in tight loops: containment, closest-point, and intersection over many primitives.

It ships as a single C++20 named module (sgl). There are no headers to include and no macros to manage: consumers just import sgl;.

import sgl;

int main() {
    const sgl::vec3 a{1, 2, 3};
    const sgl::vec3 b{4, 5, 6};

    const auto c = sgl::cross(a, b);
    const auto  dir = sgl::normalized(a);

    const auto d{sgl::dot(a, b)};

    sgl::quat q = sgl::quat_from_axis_angle(sgl::vec3{0, 0, 1}, 1.57079633f);
    sgl::vec3 r = sgl::rotate(q, sgl::vec3{1, 0, 0});
}

SIMD backends

The intrinsic-level implementation is selected automatically at configure time based on the target architecture, behind one uniform API:

Architecture Backend
x86-64 SSE / AVX2 + FMA
AArch64 (Apple Silicon, ARMv8.2-A+) NEON (D-form + Q-form)

Both backends expose the exact same sgl:: names, so code written against one compiles unchanged against the other.

What it supports

  • Vectors: vec2, vec3, vec4 (and integer ivec2/ivec3): full arithmetic operators, dot/cross, length, several normalization variants (precise, fast-reciprocal, Newton-Raphson, and zero-safe), projection, reflection, clamp/lerp/min/max/abs, distance, angle, and parallel/perpendicular tests.
  • Matrices: mat2 and mat4 (column-major): add/sub/scale/negate, multiply, transpose, determinant, trace, a general inverse plus dedicated closed-form rigid and uniform-affine inverses; mat3 is carried as a rotation/normal block with mat3<->mat4 conversions.
  • Quaternions: quat: Hamilton product, conjugate/inverse, normalization, vector rotation, axis-angle construction, matrix conversions, and angular distance.
  • Axis-aligned boxes: box2d, box3d: validity, center/extents, translate/scale/dilate, overlap/containment, intersection/merge/expand, closest-point and distance queries, area/volume/surface-area.
  • Planes & transforms: plane, plane_basis, transform: plane construction and signed-distance/projection queries, 3D<->2D plane-basis projection (with batch variants), and full TRS transform composition, inversion, and point/direction application.
  • Intersection & spatial queries: 2D segment intersection, ray and segmentAABB tests, closest distance between two 3D segments (for capsule/clearance checks), point-in-polygon (winding number), segmentpolygon, and integer grid-cell mapping.

Design notes

  • SIMD-first, one API across backends. Every operation is built on intrinsics rather than scalar fallbacks, and the AVX2 and NEON backends export identical names; the SIMD layer is an implementation detail, not part of the surface. Templates carry the weight that boilerplate usually does, which is why the surface above fits in a compact codebase.
  • Closed-form transform inverses. Rigid (R | t) and uniform-scale affine transforms are inverted by exploiting their orthogonality — transpose the rotation, remap the translation — rather than running the general cofactor/determinant inverse. For those transform classes that is the same result for a fraction of the arithmetic; the general inverse remains available when the matrix is arbitrary.

Requirements

  • CMake >= 3.30 (for CXX_MODULES install/export support)
  • GCC >= 14, Clang >= 17, or MSVC >= 19.40 (VS 2022 17.10); each is the floor for C++20 named modules plus CWG 2518 (static_assert(false) in uninstantiated template branches)
  • A C++20 standard library and toolchain with named-module support

Building

cmake -B build -G Ninja
cmake --build build

Use the Ninja or Visual Studio generator. CMake's C++20 module support does not work with the Makefiles generators.

Toolchains

sgl builds with GCC, Clang (libstdc++ or libc++), and MSVC. All three are verified in C++20 mode; the ISA flags (-mavx2 -mfma / /arch:AVX2) are applied automatically per compiler frontend.

# GCC (libstdc++)
CXX=g++ cmake -B build -G Ninja

# Clang + libc++
CXX=clang++ cmake -B build -G Ninja -DCMAKE_CXX_FLAGS="-stdlib=libc++"

# MSVC (x64 Native Tools prompt, or a cross wrapper), Ninja generator
cmake -B build -G Ninja

Then cmake --build build as usual.

Consuming

The most robust way to consume a C++20 module library is to build it as part of your tree (add_subdirectory or FetchContent) and link the sgl::sgl target:

target_link_libraries(your_target PRIVATE sgl::sgl)

Installing and using find_package is also supported (see below).

Ordering note (GCC): put textual #includes before any import sgl; in a translation unit. Importing first and #include-ing standard headers afterwards can trip a libstdc++ redefinition error.

Installing

cmake -B build -G Ninja -DCMAKE_INSTALL_PREFIX=/your/prefix
cmake --build build
cmake --install build

This installs the static archive, the arch-selected module source (consumers recompile the BMI against their own toolchain, BMIs are not portable), and a package config. Then, from another project:

find_package(sgl REQUIRED)
target_link_libraries(your_target PRIVATE sgl::sgl)

The exported target carries the x86-64 ISA flags as a usage requirement (-mavx2 -mfma, or /arch:AVX2 under MSVC), so your build compiles the imported module interface with the matching instruction set.

Options

Option Default Description
SGL_TESTS OFF Build the GoogleTest unit-test suite
SGL_PIC OFF Build with position-independent code
SGL_INSTALL top-level only Generate install + find_package() rules

Running the tests

cmake -B build -G Ninja -DSGL_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure

Each case is registered with CTest (gtest_discover_tests), so you can add -j<N> to run them in parallel, -R <regex> to select a subset, and --rerun-failed to re-run only the previous failures. The binary can also be run directly for the fastest single-shot run: ./build/tests/unit_tests.