/* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ namespace Magnum { /** @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: @ref Math::RectangularMatrix, (square) @ref Math::Matrix and @ref Math::Vector. To achieve greatest code reuse, %Matrix is internally square %RectangularMatrix and %RectangularMatrix is internally array of one or more %Vector instances. Both vectors and matrices can have arbitrary size (known at compile time) and can store any arithmetic type. Each subclass brings some specialization to its superclass and for most common vector and matrix sizes there are specialized classes @ref Math::Matrix3 and @ref Math::Matrix4, implementing various transformations in 2D and 3D, @ref Math::Vector2, @ref Math::Vector3 and @ref Math::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, e.g. @ref Color3 and @ref Color4 for color handling and conversion. Commonly used types have convenience aliases in @ref Magnum namespace, so you can write e.g. `%Vector3i` instead of `%Math::Vector3`. See @ref types and namespace documentation for more information. @section matrix-vector-construction Constructing matrices and vectors Default constructors of @ref Math::RectangularMatrix and @ref Math::Vector (and @ref Math::Vector2, @ref Math::Vector3, @ref Math::Vector4, @ref Color3) create zero-filled objects. @ref Math::Matrix (and @ref Math::Matrix3, @ref Math::Matrix4) is by default constructed as identity matrix. @ref Color4 has alpha value set to opaque. @code Matrix2x3 a; // zero-filled Vector3i b; // zero-filled Matrix3 identity; // diagonal set to 1 Matrix3 zero(Matrix::Zero); // zero-filled Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} BasicColor4 black2; // {0, 0, 0, 255} @endcode Most common and most efficient way to create vector is to pass all values to constructor, matrix is created by passing all column vectors to the constructor. @code Vector3i vec(0, 1, 2); Matrix3 mat({0.0f, 1.9f, 2.2f}, {3.5f, 4.0f, 5.1f}, {6.0f, 7.3f, 8.0f}); @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 or you can create diagonal matrix from vector: @code Matrix3 diag(Matrix3::Identity, 2.0f); // diagonal set to 2.0f, zeros elsewhere Vector3i fill(10); // {10, 10, 10} auto diag2 = Matrix3::fromDiagonal({3.0f, 2.0f, 1.0f}); @endcode It is possible to create matrices from other matrices and vectors with the same row count; vectors from vector and scalar: @code Math::RectangularMatrix<2, 3, Int> a; Math::Vector<3, Int> b, c; Math::Matrix3 mat(a, b); Math::Vector<8, Int> vec(1, b, 2, c); @endcode @todo Implement this ^ already. 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 *explicitly* convert between data types: @code Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f); auto integral = Vector4i(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 Matrix3x2 a; a[2] /= 2.0f; // third column (column major indexing, see explanation below) a[0][1] = 5.3f; // first column, second element Vector3i b; b[1] = 1; // second element @endcode Row vectors can be accessed too, but only for reading, and the access is slower due to the way the matrix is stored (see explanation below): @code Vector2i c = a.row(2); // third row @endcode Fixed-size vector subclasses have functions for accessing named components and subparts: @code Vector4i a; Int x = a.x(); a.y() += 5; Vector3i xyz = a.xyz(); xyz.xy() *= 5; @endcode Color3 and Color4 name their components `rgba` instead of `xyzw`. For more involved operations with components there is the @ref swizzle() function: @code Vector4i original(-1, 2, 3, 4); Vector4i bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } Math::Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 } @endcode @section matrix-vector-operations Operations with matrices and vectors Vectors can be added, subtracted, negated and multiplied or divided with scalars, as is common in mathematics, Magnum also adds the ability to divide scalar with vector: @code Vector3 a(1.0f, 2.0f, 3.0f); Vector3 b = a*5.0f - Vector3(3.0f, -0.5f, -7.5f); // b == {5.0f, 9.5f, 7.5f} Vector3 c = 1.0f/a; // c == {1.0f, 0.5f, 0.333f} @endcode As in GLSL, vectors can be also multiplied or divided component-wise: @code Vector3 a(1.0f, 2.0f, 3.0f); Vector3 b = a*Vector3(-0.5f, 2.0f, -7.0f); // b == {-0.5f, 4.0f, -21.0f} @endcode When working with integral vectors (i.e. 24bit RGB values), it is often desirable to multiply them with floating-point values but with integral result. In %Magnum all mulitplication/division operations involving integral vectors will have integral result, you need to convert both arguments to the same floating-point type to have floating-point result. @code BasicColor3 color(80, 116, 34); BasicColor3 lighter = color*1.5f; // lighter = {120, 174, 51} Vector3i a(4, 18, -90); Vector3 multiplier(2.2f, 0.25f, 0.1f); Vector3i b = a*multiplier; // b == {8, 4, -9} Vector3 c = Vector3(a)*multiplier; // c == {8.0f, 4.5f, -9.0f} @endcode You can use also all bitwise operations on integral vectors: @code Vector2i size(256, 256); Vector2i mipLevel3Size = size >> 3; // == {32, 32} @endcode Matrices can be added, subtracted and multiplied with matrix multiplication. @code Matrix3x2 a; Matrix3x2 b; Matrix3x2 c = a + (-b); Matrix2x3 d; Matrix2x2 e = d*b; Matrix3x3 f = b*d; @endcode You can also multiply (properly sized) vectors with matrices. These operations are just convenience shortcuts for multiplying with single-column matrices: @code Matrix3x4 a; Vector3 b; Vector4 c = a*b; Math::RectangularMatrix<4, 1, Float> d; Matrix4x3 e = b*d; @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 Math::RectangularMatrix<2, 3, Int> mat; // two columns, three rows @endcode - Order of components in matrix constructors is also column-major, further emphasized by requirement that you have to pass directly column vectors: @code Math::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, thus the bracket operator is accessing columns. Returned vector has also its own bracket operator, which is then indexing rows. @code mat[0] *= 2; // first column mat[2][0] = 5; // first element of third column @endcode - Various algorithms which commonly operate on matrix rows (such as @ref Algorithms::gaussJordanInPlace() "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. */ }}