Type system
Type aliases, naming and compatibility with OpenGL and GLSL types.
Contents
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::int
and GLint
all refer to the same type).
Magnum type | Size | Equivalent GLSL type |
---|---|---|
UnsignedByte | 8bit unsigned | |
Byte | 8bit signed | |
UnsignedShort | 16bit unsigned | |
Short | 16bit signed | |
UnsignedInt | 32bit unsigned | uint |
Int | 32bit signed | int |
UnsignedLong | 64bit unsigned | |
Long | 64bit signed | |
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 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 type | Equivalent GLSL type |
---|---|
Vector2, Vector3, Color3 Vector4, Color4 | vec2 , vec3 , vec4 |
Vector2ui, Vector3ui, Vector4ui | uvec2 , uvec3 , uvec4 |
Vector2i, Vector3i, Vector4i | ivec2 , ivec3 , ivec4 |
Vector2d, Vector3d, Vector4d | dvec2 , dvec3 , dvec4 |
Color3ub, Color4ub | (none) |
Magnum matrix type | Equivalent GLSL type |
---|---|
Matrix2x2 or Matrix2x2d | mat2 / mat2x2 or dmat2 / dmat2x2 |
Matrix3 / Matrix3x3 or Matrix3d / Matrix3x3d | mat3 / mat3x3 or dmat3 / dmat3x3 |
Matrix4 / Matrix4x4 or Matrix4d / Matrix4x4d | mat4 / mat4x4 or dmat4 / dmat4x4 |
Matrix2x3 or Matrix2x3d | mat2x3 or dmat2x3 |
Matrix3x2 or Matrix3x2d | mat3x2 or dmat3x2 |
Matrix2x4 or Matrix2x4d | mat2x4 or dmat2x4 |
Matrix4x2 or Matrix4x2d | mat4x2 or dmat4x2 |
Matrix3x4 or Matrix3x4d | mat3x4 or dmat3x4 |
Matrix4x3 or Matrix4x3d | mat4x3 or dmat4x3 |
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 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 _
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 _
using namespace Math::Literals; Half a = 3.5_h; // 0x4300 internally
Other types
Other types, which don't have their GLSL equivalent, are:
- QuadraticBezier2D or QuadraticBezier2Dd, QuadraticBezier3D or QuadraticBezier3Dd
- CubicBezier2D or CubicBezier2Dd, CubicBezier3D or CubicBezier3Dd
- Complex or Complexd, DualComplex or DualComplexd
- Frustum or Frustumd
- Quaternion or Quaterniond, DualQuaternion or DualQuaterniond
- 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 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);