# `gliso`
A [GLSL][]/[OpenGL][] [\>=2.1][] [isometry][] matrix library.
If a `mat4` matrix represents an [isometry][], which in this case means that it
encodes only rotations and translations (no scaling or shearing, and a
projective `w` entry equal to `1`), it is easy and performant to extract those
rotations and translations, and to compute the [inverse][]. This library
provides functions to do so.
[`gliso`]: https://git.rcrnstn.net/rcrnstn/gliso
[GLSL]: https://en.wikipedia.org/wiki/OpenGL_Shading_Language
[OpenGL]: https://en.wikipedia.org/wiki/OpenGL
[\>=2.1]: https://en.wikipedia.org/wiki/OpenGL#Version_history
[isometry]: https://en.wikipedia.org/wiki/Isometry
[inverse]: https://en.wikipedia.org/wiki/Invertible_matrix
## Requirements
Support for `#include` directives is required. This can be provided by e.g. the
standardized [`ARB_shading_language_include`][] extension or some third party
library.
[`ARB_shading_language_include`]: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_shading_language_include.txt
## Usage
Link shader programs with the provided `iso.glsl`.
Include the provided `iso.h` from shaders. It declares the following functions:
-   `mat{3,4} isorot{inv}{3,4}(mat4 iso)`
    Extract (inverse) rotation.
-   `vec{3,4} isotrans{inv}{3,4}(mat4 iso)`
    Extract (inverse) translation.
    The `z` components of the `4` versions are set to `0`.
-   `mat4 isoinv(mat4 iso)`
    Compute inverse.
## Theory
For simplicity, we use the same name for both the [projective][] and
[Euclidean][] versions of vectors and transformations below.
Assume $M$ is an isometry,
$$
M v
=
\begin{pmatrix}
    r_{xx} & r_{yx} & r_{zx} & t_x \\
    r_{xx} & r_{yx} & r_{zx} & t_y \\
    r_{xx} & r_{yx} & r_{zx} & t_z \\
         0 &      0 &      0 &   1 \\
\end{pmatrix}
\begin{pmatrix}
    v_x \\
    v_y \\
    v_z \\
      1 \\
\end{pmatrix}
=
R v + t
$$
It is trivial to extract the rotation $R$ and translation $t$ directly from the
components of $M$.
Since the rotation part $R$ is [orthonormal][], its inverse is its own
transpose. The inverse of the translation is its own negation.
$$
\begin{aligned}
    R^{-1} &= R^T \\
    t^{-1} &= -t \\
\end{aligned}
$$
Assuming the $3 \mathsf{x} 3$ sub-matrix of $M^{-1}$ is $R^{-1}$, finding the
full inverse is simply a matter of finding $M^{-1}$'s fourth column $m^{-1}$:
$$
\begin{aligned}
    v
    &= M^{-1} M v \\
    &= R^{-1} (R v + t) + m^{-1} \\
    &= v + R^{-1} t + m^{-1} \\
    &\iff \\
    m^{-1} &= -R^{-1} t = R^{-1} t^{-1} \\
\end{aligned}
$$
Computing this is much faster than the built-in, general, [`inverse`][].
[projective]: https://en.wikipedia.org/wiki/Homogeneous_coordinates
[Euclidean]: https://en.wikipedia.org/wiki/Cartesian_coordinates
[orthonormal]: https://en.wikipedia.org/wiki/Orthogonal_matrix
[`inverse`]: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/inverse.xhtml
## Build system
This project has support for [CMake][], and uses [`cmake-cxx`][].
There are several ways to use this project in another CMake-based project:
-   Use [`FetchContent`][] to download it and import the targets automatically
    as part of the configure step:
    ```cmake
    include(FetchContent)
    FetchContent_Declare(project-name
        GIT_REPOSITORY https://example.com/user/project-name
    )
    FetchContent_MakeAvailable(
        project-name
    )
    ```
-   Bundle it and import the targets with [`add_subdirectory`][].
-   Use [`find_package`][] (requires that the project is [packaged](#packaging)
    or [installed](#installing)).
As usual, use [`add_dependencies`][]/[`target_link_libraries`][] to declare the
dependency.
[CMake]: https://cmake.org
[`cmake-cxx`]: https://git.rcrnstn.net/rcrnstn/cmake-cxx
[`FetchContent`]: https://cmake.org/cmake/help/v3.14/module/FetchContent.html
[`add_subdirectory`]: https://cmake.org/cmake/help/v3.14/command/add_subdirectory.html
[`find_package`]: https://cmake.org/cmake/help/v3.14/command/find_package.html
[`add_dependencies`]: https://cmake.org/cmake/help/v3.14/command/add_dependencies.html
[`target_link_libraries`]: https://cmake.org/cmake/help/v3.14/command/target_link_libraries.html
### Configure and generate
To configure and generate a build tree, use `cmake`:
```sh
cmake -B build
```
To set the [`CMAKE_BUILD_TYPE`][], pass e.g. `-DCMAKE_BUILD_TYPE=Release`.
[`cmake`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#generate-a-project-buildsystem
[`CMAKE_BUILD_TYPE`]: https://cmake.org/cmake/help/v3.14/variable/CMAKE_BUILD_TYPE.html
### Build
To build, use [`cmake --build`][]:
```sh
cmake --build build
```
[`cmake --build`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#build-a-project
### Test
To run tests, use [`ctest`][]:
```sh
(cd build && ctest --output-on-failure)
```
[`ctest`]: https://cmake.org/cmake/help/v3.14/manual/ctest.1.html
### Package
To package, use [`cpack`][]:
```sh
(cd build && cpack)
```
[`cpack`]: https://cmake.org/cmake/help/v3.14/manual/cpack.1.html
### Install
To install onto the current system, use [`cmake --install`][]:
```sh
cmake --install build
```
[`cmake --install`]: https://cmake.org/cmake/help/v3.14/manual/cmake.1.html#install-a-project
## License
Licensed under the [ISC License][] unless otherwise noted, see the
[`LICENSE`](LICENSE) file.
[ISC License]: https://choosealicense.com/licenses/isc/