Feature guide » Type system

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

The root Magnum namespace defines a few aliases for essential types. See its documentation for more information about usage with CMake.

Builtin types

Magnum provides typedefs for builtin integral and floating-point arithmetic types to ensure portability (e.g. Int is always 32bit), maintain consistency and reduce confusion (e.g. std::int32_t, int and GLint all refer to the same type).

Magnum typeSizeEquivalent GLSL type
UnsignedByte8bit unsigned
Byte8bit signed
UnsignedShort16bit unsigned
Short16bit signed
UnsignedInt32bit unsigneduint
Int32bit signedint
UnsignedLong64bit unsigned
Long64bit signed
Half16bit(none)
Float32bitfloat
Double64bitdouble

Types not meant to be used in arithmetic (such as bool or std::size_t) or types which cannot be directly passed to GLSL shaders (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, ui means UnsignedInt underlying type, i is Int underlying type and d is for Double underlying type.

Matrix/vector types

Magnum vector typeEquivalent GLSL type
Vector2, Vector3, Color3 Vector4, Color4vec2, vec3, vec4
Vector2ui, Vector3ui, Vector4uiuvec2, uvec3, uvec4
Vector2i, Vector3i, Vector4iivec2, ivec3, ivec4
Vector2d, Vector3d, Vector4ddvec2, dvec3, dvec4
Color3ub, Color4ub(none)
Magnum matrix typeEquivalent GLSL type
Matrix2x2 or Matrix2x2dmat2 / mat2x2 or dmat2 / dmat2x2
Matrix3 / Matrix3x3 or Matrix3d / Matrix3x3dmat3 / mat3x3 or dmat3 / dmat3x3
Matrix4 / Matrix4x4 or Matrix4d / Matrix4x4dmat4 / mat4x4 or dmat4 / dmat4x4
Matrix2x3 or Matrix2x3dmat2x3 or dmat2x3
Matrix3x2 or Matrix3x2dmat3x2 or dmat3x2
Matrix2x4 or Matrix2x4dmat2x4 or dmat2x4
Matrix4x2 or Matrix4x2dmat4x2 or dmat4x2
Matrix3x4 or Matrix3x4dmat3x4 or dmat3x4
Matrix4x3 or Matrix4x3dmat4x3 or dmat4x3

Any super- or sub-class of the same size and underlying type can be used equivalently (e.g. Math::Vector<Float> or Color3 instead of Vector3).

For easier entering of (s)RGB colors in hexadecimal format there are _srgb / _srgbf, _srgba / _srgbaf, _rgb / _rgbf and _rgba / _rgbaf literals in Math::Literals namespace. See their documentation for more information about the differences.

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 GLSL equivalent are verified to be exactly the same as corresponding GL* types. Matrix and vector classes 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 data() function, which returns pointer to the internal data array.

Special types

Magnum has special type for strongly-typed representation of angles, namely the Deg and Rad classes (or Degd and Radd with Double as underlying type). Their only purpose is to avoid common degree-vs-radian bugs (i.e. entering degree value where radians should be) 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, so using them won't have any performance or usability impact in practice.

These classes are not implicitly constructible or convertible from/to Float or Double, you have to either construct/convert them explicitly or use custom _degf / _deg and _radf / _rad literals that are provided in the Math::Literals namespace:

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);

There is also a Half type for handling half-precision floating point values. By design it doesn't support any arithmetic operations as they would be done faster on single-precision, it's sole purpose is to make working with half-float values easier. It provides either explicit constructors and conversion operators from/to Float and UnsignedShort and you can also use the _h literal that is provided in the Math::Literals namespace:

using namespace Math::Literals;

Half a = 3.5_h;         // 0x4300 internally

Other types

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

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 alias for class with often used constants — Constants or Constantsd.

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).
  • Math::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{Math::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);