# Math type system

Type aliases, naming and compatibility with OpenGL, Vulkan and GLSL types.

Magnum defines a variety of scalar, vector and matrix types. Most of the functionality is implemented using template classes in the Math library, with the most common variants brought as typedefs into the root Magnum namespace.

## Builtin types

Magnum provides its own typedefs for builtin integral and floating-point arithmetic types to ensure portability, maintain consistency and reduce confusion. E.g., the Int typedef is guaranteed to *always* be 32-bit and Magnum's own code and documentation prefers to use it over a wild mixture of std::`int`

, `GLint`

or `ALint`

that all refer to the same type.

Magnum type | Size | Equivalent GLSL type |
---|---|---|

UnsignedByte | 8bit unsigned | (none) |

Byte | 8bit signed | (none) |

UnsignedShort | 16bit unsigned | (none) |

Short | 16bit signed | (none) |

UnsignedInt | 32bit unsigned | `uint` |

Int | 32bit signed | `int` |

UnsignedLong | 64bit unsigned | (none) |

Long | 64bit signed | (none) |

Half | 16bit | (none) |

Float | 32bit | `float` |

Double | 64bit | `double` |

Types not meant to be used in arithmetic (such as `bool`

or `std::size_t`

) or types which have no use in GPU computations (such as `long double`

) have no typedefs.

Types from the above table are then used to define other types. All following types are aliases of corresponding types in Math namespace. No suffix after type name means Float underlying type, `h`

means Half, `d`

is Double, `ub`

UnsignedByte, `b`

Byte, `us`

UnsignedShort, `s`

Short, `ui`

UnsignedInt and `i`

is Int.

## Matrix/vector types

Magnum vector type | Equivalent GLSL type |
---|---|

BitVector2, BitVector3, BitVector4 | `bvec2` , `bvec3` , `bvec4` |

Vector2, Vector3, Color3, Vector4, Color4 | `vec2` , `vec3` , `vec4` |

Vector2h, Vector3h, Color3h, Vector4h, Color4h | (none) |

Vector2d, Vector3d, Vector4d | `dvec2` , `dvec3` , `dvec4` |

Vector2ub, Vector3ub, Vector4ub, Color3ub, Color4ub | (none) |

Vector2b, Vector3b, Vector4b | (none) |

Vector2us, Vector3us, Vector4us, Color3us, Color4us | (none) |

Vector2s, Vector3s, Vector4s | (none) |

Vector2ui, Vector3ui, Vector4ui | `uvec2` , `uvec3` , `uvec4` |

Vector2i, Vector3i, Vector4i | `ivec2` , `ivec3` , `ivec4` |

Magnum matrix type | Equivalent GLSL type |
---|---|

Matrix2x2 or Matrix2x2d | `mat2` / `mat2x2` or `dmat2` / `dmat2x2` |

Matrix2x2h, Matrix2x2b, Matrix2x2s | (none) |

Matrix3 / Matrix3x3 or Matrix3d / Matrix3x3d | `mat3` / `mat3x3` or `dmat3` / `dmat3x3` |

Matrix3x3h, Matrix3x3b, Matrix3x3s | (none) |

Matrix4 / Matrix4x4 or Matrix4d / Matrix4x4d | `mat4` / `mat4x4` or `dmat4` / `dmat4x4` |

Matrix4x4h, Matrix4x4b, Matrix4x4s | (none) |

Matrix2x3 or Matrix2x3d | `mat2x3` or `dmat2x3` |

Matrix2x3h, Matrix2x3b, Matrix2x3s | (none) |

Matrix3x2 or Matrix3x2d | `mat3x2` or `dmat3x2` |

Matrix3x2h, Matrix3x2b, Matrix3x2s | (none) |

Matrix2x4 or Matrix2x4d | `mat2x4` or `dmat2x4` |

Matrix2x4h, Matrix2x4b, Matrix2x4s | (none) |

Matrix4x2 or Matrix4x2d | `mat4x2` or `dmat4x2` |

Matrix4x2h, Matrix4x2b, Matrix4x2s | (none) |

Matrix3x4 or Matrix3x4d | `mat3x4` or `dmat3x4` |

Matrix3x4h, Matrix3x4b, Matrix3x4s | (none) |

Matrix4x3 or Matrix4x3d | `mat4x3` or `dmat4x3` |

Matrix4x3h, Matrix4x3b, Matrix4x3s | (none) |

Any super- or sub-class of the same size and underlying type can be used equivalently (e.g. Math::

For easier entering of (s)RGB colors in hexadecimal format there are _

using namespace Math::Literals; Color3 a = 0x33b27f_srgbf; // {0.0331048f, 0.445201f, 0.212231f} Color4ub b = 0x33b27fcc_rgba; // {0x33, 0xb2, 0x7f, 0xcc}

## Binary representation

Scalar types with a GLSL equivalent are guaranteed to have exactly the same binary representation. Consequently, matrix and vector classes also have the same binary representation as corresponding array of numeric values without any additional data or padding (e.g. `sizeof(Vector3i) == sizeof(Int[3])`

). All matrices are stored in column-major order.

This means that all scalar, matrix and vector types can be used directly for filling GPU buffers and textures without any need for data extraction or conversion. For convenience all vector and matrix classes provide a data() function, which returns a pointer to the internal data array.

## Half-precision arithmetic

The Half type represents half-precision floating point values. The sole purpose of the type is to make creation, conversion and visualization of half-float values easier. By design it doesn't support any arithmetic operations as not all CPU architecture have native support for half-floats and thus the operations would be done faster in a regular single-precision Float. The class provides explicit constructors and conversion operators from/to Float and UnsignedShort and you can also use the _

using namespace Math::Literals; Half a = 3.5_h; // 0x4300 internally

Half-precision vector and matrix types such as Vector3h or Matrix3x3h work similarly — you can construct them and convert them from/to other types, but can't perform any arithmetic.

## Special types

Magnum has a special type for strongly-typed representation of angles, namely the Deg and Rad classes (or Degd / Degh and Radd / Radh with Double / Half as underlying type). Their purpose is to avoid common degree-vs-radian bugs (i.e. entering a degree value where radians should be and vice versa) and make the conversion between these two representations easier. They are just a tiny `constexpr`

wrapper around the native type and they support all meaningful numeric operations. The wrapper API may have a slight overhead on debug builds, but the safety benefits outweight that in most practical use cases.

These classes are *not* implicitly constructible or convertible from/to Float or Double, you have to either construct/convert them explicitly or use custom _

using namespace Math::Literals; //Deg a = 60.0f // error, no implicit conversion from Float Deg a = 60.0_degf; // okay Float b = 3.2831853f; auto tau = Rad{b} + 3.0_radf; Radd pi = 3.141592653589793_rad; //Double c = pi; // error, no implicit conversion to Double auto c = Double(pi); // okay

They can be implicitly converted to each other, but conversion to different underlying type is *explicit* to avoid precision loss (or, on the other hand, unnecessarily high precision) during computations:

Rad d = 60.0_degf; // 1.0471976f auto e = Degd{pi}; // 180.0 //Rad f = pi; // error, no implicit conversion of underlying types auto f = Rad{pi}; // 3.141592654f

These classes are used exclusively in all functions taking and returning angles — trigonometry, angle computation, rotating transformation etc. Thanks to implicit conversion you can seamlessly use either radians or degrees without any need to care about what input the function expects:

Float a = Math::sin(1.32457_radf); Complex b = Complex::rotation(60.0_degf);

## Other types

Other types, which don't have their GLSL equivalent, are:

- QuadraticBezier2D or QuadraticBezier2Dd, QuadraticBezier3D or QuadraticBezier3Dd
- CubicBezier2D or CubicBezier2Dd, CubicBezier3D or CubicBezier3Dd
- CubicHermite1D or CubicHermite1Dd, CubicHermite2D or CubicHermite2Dd, CubicHermite3D or CubicHermite3Dd
- Complex or Complexd, DualComplex or DualComplexd
- Frustum or Frustumd
- Quaternion or Quaterniond, DualQuaternion or DualQuaterniond
- CubicHermiteComplex or CubicHermiteComplexd
- CubicHermiteQuaternion or CubicHermiteQuaterniond
- Range1D / Range2D / Range3D, Range1Di / Range2Di / Range3Di or Range1Dd / Range2Dd / Range3Dd

These types can be used in GLSL either by extracting values from their underlying structure or converting them to types supported by GLSL (e.g. quaternion to matrix).

For your convenience, there is also a structure with often used constants — Constants, or Constantsd for the double-precision variants.

## Initialization

Vectors, general matrices and range types are by default zero-initialized, transformation types (square matrices, (dual) complex numbers and quaternions) are set to identity transformation. It is possible to initialize the instances differently using so-called *tags* or use the tag to make the choice appear explicit:

- Math::
ZeroInit zero-initializes the contents (works for all types). - Math::
IdentityInit initializes the contents to identity transformation (works only for transformation types, where it is also the default). - NoInit leaves the contents uninitialized (useful if you will overwrite the contents anyway, works for all types).

Example:

/* These are equivalent */ Vector3 a1; Vector3 a2{Math::ZeroInit}; /* These too */ Quaternion q1; Quaternion q2{Math::IdentityInit}; /* Avoid unnecessary initialization if is overwritten anyway */ Matrix4 projection{NoInit}; if(orthographic) projection = Matrix4::orthographicProjection({4.0f, 3.0f}, 0.1f, 100.0f); else projection = Matrix4::perspectiveProjection(35.0_degf, 1.33f, 0.1f, 100.0f);

## Integration with types from 3rd party APIs

To simplify the workflow when interacting with 3rd party APIs, all Magnum math types can be made explicitly convertible to and from types coming from external libraries. Currently, various Magnum libraries provide these conversion, see documentation of each `Integration.h`

header for details:

- Math-related Vulkan structures — Magnum/
Vk/ , part of the Vk libraryIntegration.h - All Eigen types — Magnum/
EigenIntegration/ and Magnum/Integration.h EigenIntegration/ , part of the EigenIntegration libraryGeometryIntegration.h - All GLM types — Magnum/
GlmIntegration/ , Magnum/Integration.h GlmIntegration/ and Magnum/GtcIntegration.h GlmIntegration/ , part of the GlmIntegration libraryGtxIntegration.h - Bullet Physics math types — Magnum/
BulletIntegration/ , part of the BulletIntegration libraryIntegration.h - Oculus VR SDK math types – Magnum/
OvrIntegration/ , part of the OvrIntegration libraryIntegration.h - Dear ImGui math types — Magnum/
ImGuiIntegration/ , part of the ImGuiIntegration libraryIntegration.h