diff --git a/doc/mainpage.dox b/doc/mainpage.dox index c0838794f..fd394ae85 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -4,8 +4,9 @@ namespace Magnum { %Magnum is 3D graphics engine written in C++11 and OpenGL 3 Core Profile. Features: -- Easy-to-use templated @ref Math "mathematical library" for matrix/vector - calculations and @ref Math::Geometry "geometry". +- Easy-to-use templated @ref Math "mathematical library" for + @ref matrix-vector "matrix/vector calculations" and + @ref Math::Geometry "geometry". - Classes wrapping OpenGL objects and simplifying their usage - @ref AbstractShaderProgram "shaders", @ref Buffer "buffers", @ref Mesh "meshes" and @ref AbstractTexture "textures". Access to diff --git a/doc/matrix-vector.dox b/doc/matrix-vector.dox new file mode 100644 index 000000000..795f5619c --- /dev/null +++ b/doc/matrix-vector.dox @@ -0,0 +1,181 @@ +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. +*/ +}} diff --git a/doc/namespaces.dox b/doc/namespaces.dox index faf2cb178..ff7bf5656 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -25,7 +25,8 @@ Base classes for creating OpenGL contexts with various toolkits. /** @namespace Magnum::Math @brief %Math library -Template classes for matrix and vector calculations. +Template classes for matrix and vector calculations. See @ref matrix-vector +for brief introduction. */ /** @dir Math/Algorithms diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index 2273ce3b1..30e6c1e2e 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -32,6 +32,9 @@ namespace Implementation { /** @brief Square matrix @tparam s %Matrix size +@tparam T Data type + +See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Matrix} @todo @c PERFORMANCE - loop unrolling for Matrix<3, T> and Matrix<4, T> @@ -228,7 +231,6 @@ namespace Implementation { template class MatrixDeterminant { public: - /** @brief Functor */ T operator()(const Matrix& m) { T out(0); @@ -241,7 +243,6 @@ template class MatrixDeterminant { template class MatrixDeterminant<2, T> { public: - /** @brief Functor */ inline constexpr T operator()(const Matrix<2, T>& m) { return m(0, 0)*m(1, 1) - m(1, 0)*m(0, 1); } @@ -249,7 +250,6 @@ template class MatrixDeterminant<2, T> { template class MatrixDeterminant<1, T> { public: - /** @brief Functor */ inline constexpr T operator()(const Matrix<1, T>& m) { return m(0, 0); } diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index e537de58a..fd2af1d4d 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -26,9 +26,10 @@ namespace Magnum { namespace Math { /** @brief 3x3 matrix +@tparam T Data type -Provides functions for transformations in 2D. See also Matrix4 for 3D -transformations. +Provides functions for transformations in 2D. See Matrix4 for 3D +transformations. See also @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Matrix3} */ template class Matrix3: public Matrix<3, T> { diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index e0cfceb07..2e10dda97 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -26,9 +26,10 @@ namespace Magnum { namespace Math { /** @brief 4x4 matrix +@tparam T Data type -Provides functions for transformations in 3D. See also Matrix3 for 2D -transformations. +Provides functions for transformations in 3D. See Matrix3 for 2D +transformations. See also @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Matrix4} @todo Shearing @todo Reflection diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 6c52764a8..770862565 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -48,8 +48,10 @@ template class Vector; @brief Rectangular matrix @tparam c Column count @tparam r Row count +@tparam T Data type -See also Matrix (square) and Vector. +See @ref matrix-vector for brief introduction. See also Matrix (square) and +Vector. */ template class RectangularMatrix { static_assert(c != 0 && r != 0, "Matrix cannot have zero elements"); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index da1372ee2..9d78a10ca 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -36,7 +36,10 @@ namespace Implementation { /** @brief %Vector +@tparam s %Vector size +@tparam T Data type +See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector} @todo Constexprize all for loops */ diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index 6c72d25f4..2b477a1f6 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -25,7 +25,9 @@ namespace Magnum { namespace Math { /** @brief Two-component vector +@tparam T Data type +See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector2} */ template class Vector2: public Vector<2, T> { diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index 001d615a7..095b053fd 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -25,7 +25,9 @@ namespace Magnum { namespace Math { /** @brief Three-component vector +@tparam T Data type +See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector3} */ template class Vector3: public Vector<3, T> { diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index e25c85fea..41e24f313 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -25,7 +25,9 @@ namespace Magnum { namespace Math { /** @brief Four-component vector +@tparam T Data type +See @ref matrix-vector for brief introduction. @configurationvalueref{Magnum::Math::Vector4} */ template class Vector4: public Vector<4, T> { diff --git a/src/Swizzle.h b/src/Swizzle.h index 8f30f96a5..d61ae1cdb 100644 --- a/src/Swizzle.h +++ b/src/Swizzle.h @@ -97,7 +97,8 @@ swizzle(const T&, const char(&)[newSize]), but the evaluation of the swizzling operation is guaranteed to be always done at compile time instead of at runtime. -@see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy() +@see @ref matrix-vector-component-access, Vector4::xyz(), Color4::rgb(), + Vector4::xy(), Vector3::xy() */ template inline constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector) { return {vector[Implementation::GetComponent::value()]...}; @@ -123,7 +124,8 @@ swizzle(const T&), but unless the result is marked with `constexpr`, the evaluation of the swizzling operation probably won't be evaluated at compile time, but at runtime. -@see Vector4::xyz(), Vector4::rgb(), Vector4::xy(), Vector3::xy() +@see @ref matrix-vector-component-access, Vector4::xyz(), Color4::rgb(), + Vector4::xy(), Vector3::xy() */ template inline constexpr typename Implementation::TypeForSize::Type swizzle(const T& vector, const char(&components)[newSize]) { return Implementation::swizzleFrom(typename Implementation::GenerateSequence::Type(), vector, components);