/*
    This file is part of Magnum.

    Copyright © 2010, 2011, 2012, 2013, 2014
              Vladimír Vondruš <mosra@centrum.cz>

    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.

-   Previous page: @ref types
-   Next page: @ref transformations

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. They
are contained in @ref Math namespace and common variants also have aliases in
root @ref Magnum namespace. See documentation of these namespaces for more
information about usage with CMake.

@tableofcontents

@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<Int>`. 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}
Color4ub 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. All constructors check number of passed arguments and the errors
are catched at compile time.
@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

You can specify all components of vector or whole diagonal of square matrix
with single value or 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::Matrix2x3<Int> a;
Math::Vector3<Int> b, c;
Math::Matrix3<Int> 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 };
Math::Matrix2x3<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.

@section matrix-vector-component-access Accessing matrix and vector components

Column vectors of matrices and vector components can be accessed using square
brackets:
@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 @ref matrix-vector-column-major "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-conversion Converting between different underlying types

All vector, matrix and other classes in @ref Math namespace and also
@ref Color3 and @ref Color4 classes are able to be constructed from type with
different underlying type (e.g. convert between integer and floating-point or
betweeen @ref Float and @ref Double). Unlike with plain C++ data types, the
conversion is done via *explicit* constructor. That might sound inconvenient,
but doing the conversion explicitly avoids common issues like precision loss
(or, on the other hand, doing computations in unnecessarily high precision).

To further emphasise the intent of conversion (so it doesn't look like accident
or typo), you are encouraged to use `auto b = Type{a}` instead of `Type b{a}`.
@code
Vector3 a{2.2f, 0.25f, -5.1f};
//Vector3i b = a;                // error, implicit conversion not allowed
auto c = Vector3i{a};            // {2, 0, -5}
auto d = Vector3d{a};            // {2.2, 0.25, -5.1}
@endcode

For normalizing and denormalizing there are @ref Math::normalize() and
@ref Math::denormalize() functions:
@code
Color3 a{0.8f, 1.0f, 0.3f};
auto b = Math::denormalize<Color3ub>(a);    // {204, 255, 76}

Color3ub c{64, 127, 89};
auto d = Math::normalize<Color3>(c);        // {0.251, 0.498, 0.349}
@endcode

See @ref matrix-vector-componentwise "below" for more information about other
available component-wise operations.

@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
Color3ub color(80, 116, 34);
Color3ub 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-componentwise Component-wise and inter-vector operations

As shown above, vectors can be added and multiplied component-wise using the
`+` or `*` operator. You can use @ref Math::Vector::sum() "sum()" and
@ref Math::Vector::product() "product()" for sum or product of components in
one vector:
@code
Float a = Vector3{1.5f, 0.3f, 8.0f}.sum();  // 8.8f
Int b = Vector3i{32, -5, 7}.product()       // 1120
@endcode

Component-wise minimum and maximum of two vectors can be done using
@ref Math::min(), @ref Math::max() or @ref Math::minmax(), similarly with
@ref Vector::min() "min()", @ref Vector::max() "max()" and
@ref Vector2::minmax() "minmax()" for components in one vector.
@code
Vector3i a{-5, 7, 24};
Vector3i b{8, -2, 12};

Vector3i min = Math::min(a, b); // {-5, -2, 12}
Int max = a.max();              // 24
@endcode

The vectors can be also compared component-wise, the result is returned in
@ref Math::BoolVector class:
@code
BoolVector<3> largerOrEqual = a >= b;   // {false, true, true}
bool anySmaller = (a < b).any();        // true
bool allLarger = (a > b).all();         // false
@endcode

There are also function for component-wise rounding, sign operations, square
root, various interpolation and (de)normalization functionality:
@code
Vector3 a{5.5f, -0.3f, 75.0f};
Vector3 b = Math::round(a);                 // {5.0f,  0.0f, 75.0f}
Vector3 c = Math::abs(a);                   // {5.5f, -0.3f, 75.0f}
Vector3 d = Math::clamp(a, -0.2f, 55.0f);   // {5.5f, -0.2f, 55.0f}
@endcode

Component-wise functions are implemented only for vectors and not for matrices
to keep the math library in sane and maintainable size. Instead, you can
reinterpret the matrix as vector and do the operation on it (and vice versa):
@code
Matrix3x2 mat;
Math::Vector<6, Float> vec = mat.toVector();
// ...
mat = Matrix3x2::fromVector(vec);
@endcode

Note that all component-wise functions in Math namespace work also for scalars:
@code
std::pair<Int, Int> minmax = Math::minmax(24, -5);  // -5, 24
Int a = Math::lerp(0, 360, 0.75f);                  // 270
auto b = Math::denormalize<UnsignedByte>(0.89f);    // 226
@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 @ref Math::RectangularMatrix
  is also column-major:
@code
Math::RectangularMatrix<2, 5, Int> mat; // two columns, five 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<Int> 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.

&nbsp;

-   Previous page: @ref types
-   Next page: @ref transformations
*/
}
