namespace Magnum { namespace Math { /** @page matrix-vector Operations with matrices and vectors @brief Introduction to essential classes of the graphics pipeline. @tableofcontents Matrices and vectors are the most important part of graphics programming and one of goals of %Magnum is to make their usage as intuitive as possible. This page will overview their usage and introduce some tricks to make your life easier. @section matrix-vector-hierarchy Matrix and vector classes %Magnum has three main matrix and vector classes: RectangularMatrix, (square) Matrix and Vector. To achieve greatest code reuse, %Matrix is internally square %RectangularMatrix and %Vector is internally one-column %RectangularMatrix. Both vectors and matrices can have arbitrary size (known at compile time) and can store any meaningful type. Each subclass brings some specialization to its superclass and for most common vector and matrix sizes there are specialized classes Matrix3 and Matrix4, implementing various transformation in 2D and 3D, Vector2, Vector3 and Vector4, implementing direct access to named components. Functions of each class try to return the most specialized type known to make subsequent operations more convenient - columns of %RectangularMatrix are returned as %Vector, but when accessing columns of e.g. %Matrix3, they are returned as %Vector3. There are also even more specialized subclasses - Point2D, Point3D for creating points with homogeneous coordinates and Color3, Color4 for color handling and conversion. @section matrix-vector-construction Constructing matrices and vectors Default constructors of RectangularMatrix and Vector (and Vector2, Vector3, Vector4, Color3) create zero-filled objects. Matrix (and Matrix3, Matrix4) is by default constructed as identity matrix. Point2D and Point3D have homogeneous component set to one, Color4 has alpha value set to opaque. @code RectangularMatrix<2, 3, int> a; // zero-filled Vector<3, int> b; // zero-filled Matrix<3, int> identity; // diagonal set to 1 Matrix<3, int> zero(Matrix<3, int>::Zero); // zero-filled Point2D c; // {0, 0, 1} Point3D d; // {0, 0, 0, 1} Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} Color4 black2; // {0, 0, 0, 255} @endcode Most common and most efficient way to create matrix or vector is to pass values of all components to the constructor. @code Matrix3 mat(0, 1, 2, 3, 4, 5, 6, 7, 8); // column-major (see explanation why below) Vector3 vec(0, 1, 2); @endcode All constructors check number of passed arguments and the errors are catched at compile time. You can specify all components of vector or whole diagonal of square matrix at once: @code Matrix3 diag(Matrix3::Identity, 2); // diagonal set to 2, zeros elsewhere Vector3 fill(10); // {10, 10, 10} @endcode Vectors are commonly used to specify various axes and scaling coefficients in transformations, you can use convenience functions instead of typing out all other elements: @code Matrix4::rotation(deg(5.0f), Vector3::xAxis()); // {1.0f, 0.0f, 0.0f} Matrix3::translation(Vector2::yAxis(2.0f)); // {0.0f, 2.0f} Matrix4::scaling(Vector3::zScale(-10.0f)); // {1.0f, 1.0f, -10.0f} @endcode It is possible to create matrices from other matrices and vectors with the same row count; vectors from vector and scalar: @code RectangularMatrix<2, 3, int> a; Vector3 b, c; Matrix3 mat = Matrix3::from(b, a, c); Vector<8, int> vec = Vector<8, int>::from(1, b, 2, c); @endcode It is also possible to create them from an C-style array. The function does simple type cast without any copying, so it's possible to conveniently operate on the array itself: @code int[] mat = { 2, 4, 6, 1, 3, 5 }; RectangularMatrix<2, 3, int>::from(mat) *= 2; // mat == { 4, 8, 12, 2, 6, 10 } @endcode Note that unlike constructors, this function has no way to check whether the array is long enough to contain all elements, so use with caution. You can also convert between data types: @code Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f); Vector4 integral(Vector4::from(floating)); // {1, 2, -15, 7} @endcode @section matrix-vector-component-access Accessing matrix and vector components Column vectors of matrices and vector components can be accessed using square brackets, there is also round bracket operator for accessing matrix components directly: @code RectangularMatrix<3, 2, int> a; a[2] /= 2; // third column (column major indexing, see explanation below) a[0][1] = 5; // first column, second element a(0, 1) += 3; // first column, second element (preferred) Vector<3, int> b; b[1] = 1; // second element @endcode For accessing matrix element prefer round bracket operator, as it is possibly faster than the double square brackets (but never slower) and isn't prone to compiler mis-optimizations. Fixed-size vector subclasses have functions for accessing named components and subparts: @code Vector4 a; int x = a.x(); a.y() += 5; Vector3 xyz = a.xyz(); xyz.xy() *= 5; @endcode Color3 and Color4 name their components `rgba` instead of `xyzw`. For more involved operations with components there are two swizzle() functions, they have the same features, but one is guaranteed to do most of the work at compile-time, while the second has more convenient syntax: @code Vector4 original(-1, 2, 3, 4); Vector4 bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } Vector<6, int> a10rgb = swizzle(original, "a10rgb"); // { 4, 1, 0, -1, 2, 3 } @endcode @section matrix-vector-column-major Matrices are column-major and vectors are columns OpenGL matrices are column-major, thus it is reasonable to have matrices in %Magnum also column major (and vectors as columns). This has naturally some implications and it may differ from what is common in mathematics: - Order of template arguments in specification of RectangularMatrix is also column-major: @code RectangularMatrix<2, 3, int> mat; // two columns, three rows @endcode - Order of components in matrix constructors is also column-major, so the elements passed in constructor doesn't need to be reordered internally before putting them into data array: @code Matrix3 mat(0, 1, 2, 3, 4, 5, 6, 7, 8); // first column is {0, 1, 2} @endcode - Element accessing order is also column-major. It costs virtually no time to return reference to portion of data array as column vector, thus the bracket operator is accessing columns. Returned vector has also its own bracket operator, which is indexing rows. To avoid confusion, first parameter of round bracket operator is thus also column index. @code mat[0] *= 2; // first column mat[2][0] = 5; // first element of first column vector mat(2, 0) += 3; // first element of first column @endcode - Various algorithms which commonly operate on matrix rows (such as @ref Algorithms::GaussJordan "Gauss-Jordan elimination") have faster alternatives which operate on columns. It's then up to user decision to operate with transposed matrices or use the slower non-transposed alternative of the algorithm. */ }}