Browse Source

Merge branch 'master' into compatibility

Conflicts:
	src/AbstractTexture.cpp
Vladimír Vondruš 13 years ago
parent
commit
3eef36d410
  1. 2
      Doxyfile
  2. 2
      README.md
  3. 4
      doc/best-practices.dox
  4. 6
      doc/coding-style.dox
  5. 81
      doc/compilation-speedup.dox
  6. 2
      doc/mainpage.dox
  7. 180
      doc/matrix-vector.dox
  8. 53
      doc/portability.dox
  9. 4
      src/AbstractResourceLoader.h
  10. 24
      src/AbstractTexture.cpp
  11. 2
      src/Audio/Context.h
  12. 8
      src/Color.h
  13. 2
      src/Context.h
  14. 6
      src/DimensionTraits.h
  15. 25
      src/Math/Matrix.h
  16. 4
      src/Math/Matrix3.h
  17. 4
      src/Math/Matrix4.h
  18. 102
      src/Math/RectangularMatrix.h
  19. 63
      src/Math/Test/MatrixTest.cpp
  20. 140
      src/Math/Test/RectangularMatrixTest.cpp
  21. 180
      src/Math/Test/VectorTest.cpp
  22. 16
      src/Math/TypeTraits.h
  23. 585
      src/Math/Vector.h
  24. 4
      src/Math/Vector2.h
  25. 4
      src/Math/Vector3.h
  26. 4
      src/Math/Vector4.h
  27. 6
      src/ResourceManager.h
  28. 4
      src/Shapes/AxisAlignedBox.h
  29. 8
      src/Shapes/Capsule.h
  30. 8
      src/Shapes/Cylinder.h
  31. 8
      src/Shapes/Plane.h
  32. 14
      src/Shapes/Sphere.h
  33. 2
      src/Text/DistanceFieldGlyphCache.cpp
  34. 4
      src/TextureTools/DistanceField.cpp

2
Doxyfile

@ -203,7 +203,7 @@ ALIASES = \
"debugoperator{1}=@relates \1\n@brief Debug output operator @xrefitem debugoperators \"Debug output operator\" \"Debug output operators for custom types\" Allows printing \1 with Corrade::Utility::Debug and friends." \ "debugoperator{1}=@relates \1\n@brief Debug output operator @xrefitem debugoperators \"Debug output operator\" \"Debug output operators for custom types\" Allows printing \1 with Corrade::Utility::Debug and friends." \
"configurationvalueref{1}=@see @ref configurationvalues \"Corrade::Utility::ConfigurationValue<\1>\"" \ "configurationvalueref{1}=@see @ref configurationvalues \"Corrade::Utility::ConfigurationValue<\1>\"" \
"configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \ "configurationvalue{1}=@brief %Configuration value parser and writer @xrefitem configurationvalues \"Configuration value parser and writer\" \"Configuration value parsers and writers for custom types\" Allows parsing and writing \1 from and to Corrade::Utility::Configuration." \
"collisionoperator{2}=@relates \1\n@brief Collision of %\1 and %\2\n@see \2::operator%(const \1&) const" \ "collisionoccurenceoperator{2}=@relates \1\n@brief %Collision occurence of %\1 and %\2\n@see \2::operator%(const \1&) const" \
"todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \ "todoc=@xrefitem todoc \"Documentation todo\" \"Documentation-related todo list\"" \
"fn_gl{1}=<a href=\"http://www.opengl.org/sdk/docs/man4/xhtml/gl\1.xml\">gl\1()</a>" \ "fn_gl{1}=<a href=\"http://www.opengl.org/sdk/docs/man4/xhtml/gl\1.xml\">gl\1()</a>" \
"fn_gl_extension{3}=<a href=\"http://www.opengl.org/registry/specs/\2/\3.txt\">gl\1<b></b>\2()</a>" \ "fn_gl_extension{3}=<a href=\"http://www.opengl.org/registry/specs/\2/\3.txt\">gl\1<b></b>\2()</a>" \

2
README.md

@ -1,6 +1,6 @@
Magnum is 2D/3D graphics engine written in C++11 and modern OpenGL. Its goal is Magnum is 2D/3D graphics engine written in C++11 and modern OpenGL. Its goal is
to simplify low-level graphics development and interaction with OpenGL using to simplify low-level graphics development and interaction with OpenGL using
recent C++11 features and abstract away platform-specific issues. recent C++11 features and to abstract away platform-specific issues.
DESIGN GOALS DESIGN GOALS
============ ============

4
doc/best-practices.dox

@ -33,6 +33,10 @@ Here is collection of carefully selected links to official guidelines and
other articles with valuable information to help developers create better other articles with valuable information to help developers create better
applications. Feel free to add one, if it contains new unique information. applications. Feel free to add one, if it contains new unique information.
@section best-practices-general General best practices
- [Writing Portable OpenGL ES 2.0](https://www.khronos.org/assets/uploads/developers/library/2011-siggraph-mobile/Writing-Portable-OpenGL-ES-2.0_Aug-11.pdf)
@section best-practices-platform Platform-specific @section best-practices-platform Platform-specific
Some platforms need special care, see their respective sections for more Some platforms need special care, see their respective sections for more

6
doc/coding-style.dox

@ -102,10 +102,10 @@ Additionally to @c \@todoc, @c \@debugoperator @c \@configurationvalue and
@subsubsection documentation-commands-collisionoperator Shape collision operators @subsubsection documentation-commands-collisionoperator Shape collision operators
Out-of-class operators for collision in Shapes namespace should be marked with Out-of-class operators for collision occurence in Shapes namespace should be
@c \@collisionoperator, e.g.: marked with @c \@collisionoccurenceoperator, e.g.:
@code @code
// @collisionoperator{Point,Sphere} // @collisionoccurenceoperator{Point,Sphere}
inline bool operator%(const Point& a, const Sphere& b) { return b % a; } inline bool operator%(const Point& a, const Sphere& b) { return b % a; }
@endcode @endcode
They will appear as related functions within documentation of class for which They will appear as related functions within documentation of class for which

81
doc/compilation-speedup.dox

@ -33,31 +33,31 @@ directives in both headers and source files. %Magnum is strictly applying this
policy in all header files, so all types which are not directly used in the policy in all header files, so all types which are not directly used in the
header have only forward declarations. header have only forward declarations.
For example, when including Magnum.h, you get shortcut typedefs for For example, when including @ref Magnum.h, you get shortcut typedefs for
floating-point vectors and matrices like @ref Vector3 and @ref Matrix4, but to floating-point vectors and matrices like @ref Vector3 and @ref Matrix4, but to
actually use any of them, you have to include the respective header, e.g. actually use any of them, you have to include the respective header, e.g.
Math/Vector3.h. @ref Math/Vector3.h.
You are encouraged to use forward declarations also in your code. However, for You are encouraged to use forward declarations also in your code. However, for
some types it can be too cumbersome -- e.g. too many template parameters, some types it can be too cumbersome -- e.g. too many template parameters,
typedefs etc. In this case a header with forward declarations is usually typedefs etc. In this case a header with forward declarations is usually
available, each namespace has its own: available, each namespace has its own:
- Math/Math.h - @ref Math/Math.h
- Magnum.h - @ref Magnum.h
- DebugTools/DebugTools.h - @ref DebugTools/DebugTools.h
- SceneGraph/SceneGraph.h - @ref SceneGraph/SceneGraph.h
- Shaders/Shaders.h - @ref Shaders/Shaders.h
- Shapes/Shapes.h - @ref Shapes/Shapes.h
- Text/Text.h - @ref Text/Text.h
- Trade/Trade.h - @ref Trade/Trade.h
@section compilation-speedup-templates Templates @section compilation-speedup-templates Templates
Many things in %Magnum are templated to allow handling of various types and Many things in %Magnum are templated to allow handling of various types and
sizes of data, for example whole Scene graph can operate either with @ref Float sizes of data, for example whole scene graph can operate either with @ref Float
or @ref Double data type. However, having templated classes and function usually or @ref Double data type. However, having templated classes and function
means that the compiler compiles the whole templated code again in each usually means that the compiler compiles the whole templated code again in each
compilation unit (i.e. source file). In linking stage of the application or compilation unit (i.e. source file). In linking stage of the application or
library the duplicates are just thrown out, which is a waste of compilation library the duplicates are just thrown out, which is a waste of compilation
time. A few techniques are employed in %Magnum to avoid this. time. A few techniques are employed in %Magnum to avoid this.
@ -67,48 +67,51 @@ time. A few techniques are employed in %Magnum to avoid this.
When templated code is too large, it is not stored in header file, but in When templated code is too large, it is not stored in header file, but in
so-called *template implementation file*. Generally, all header files in so-called *template implementation file*. Generally, all header files in
%Magnum have `*.h` extension and all source files have `*.cpp` extension. %Magnum have `*.h` extension and all source files have `*.cpp` extension.
Template implementation files have `*.hpp` extension (hinting that they are Template implementation files have `*.hpp` extension, hinting that they are
something between `*.h` and `*.cpp` files). something between `*.h` and `*.cpp` files.
Template implementation file can be included along the header itself and it Template implementation file can be included along the header itself and it
will just work, but it will negatively affect compilation time. If you are will just work, but it will negatively affect compilation time. If you are
using one template specialization in many places, the compiler performs using one template specialization in many places, the compiler performs
compilation of the same template specialization many times. Template compilation of the same template specialization many times, as said above.
implementation files give you the ability to explicitly instantiate the Template implementation files give you the ability to explicitly instantiate
template only once in some dedicated source file. Then you can include just the template only once in some dedicated source file. Then you can include just
the header everywhere else and leave the rest on the linker. the header everywhere else and leave the rest on the linker.
Templated classes which have implementation files state in their documentation Templated classes having code in template implementation files state in their
all common specializations that are already compiled in the libraries. So, documentation all common specializations that are already compiled in the
unless the templated class is too generic or you need something special, you libraries. So, unless the templated class is too generic or you need something
don't have to mess with template implementation files at all. See special, you don't have to mess with template implementation files at all. See
SceneGraph::Object or SceneGraph::AbstractCamera for an example. @ref SceneGraph::Object or @ref SceneGraph::AbstractCamera for an example.
Sometimes you however need to use your own specialization and that's why Sometimes, however, you need to use your own specialization and that's why
template implementation files are included in the library. For example we want template implementation files are installed along with the library. For example
to use @ref SceneGraph::Object "Object" from SceneGraph with we want to use @ref SceneGraph::Object "Object" from @ref SceneGraph with
@ref SceneGraph::MatrixTransformation3D "MatrixTransformation3D" with @ref SceneGraph::BasicMatrixTransformation3D "BasicMatrixTransformation3D" with
@ref Double as underlying type, because our scene will span the whole universe. @ref Double instead of @ref Float as underlying type, because our scene will
We include the implementation file in dedicated source file and explicitly span the whole universe. We include the implementation file in dedicated source
instantiate the template: file and explicitly instantiate the template:
@code @code
// Object.cpp // Object.cpp
#include "SceneGraph/Object.hpp" #include "SceneGraph/Object.hpp"
#include "SceneGraph/MatrixTransformation3D.h"
using namespace Magnum::SceneGraph; using namespace Magnum;
template class Object<MatrixTransformation3D<Double>>; template class SceneGraph::Object<SceneGraph::BasicMatrixTransformation3D<Double>>;
@endcode @endcode
All other files using the same object specialization now need to include only All other files using the same object specialization now need to include only
SceneGraph/Object.h header. Thus the Object specialization will be compiled @ref SceneGraph/Object.h header. Thus the @ref SceneGraph::Object "Object"
only once in our `Object.cpp` file, saving precious compilation time. specialization will be compiled only once in our `Object.cpp` file, saving
precious compilation time.
@subsection compilation-speedup-extern-templates Extern templates @subsection compilation-speedup-extern-templates Extern templates
Keyword `extern template` is new thing in C++11, attempting to solve Keyword `extern template` is a new thing in C++11, attempting to solve
compilation time problems. However, when used on whole classes, on some compilation time problems related to templated code. However, on some compilers
compilers it causes conflicting symbol errors, so in %Magnum its used only for it causes conflicting symbol errors when used on whole classes, thus in %Magnum
specific functions. it's used only for specific functions.
This is completely transparent to end user, so no special care is needed. This is completely transparent to end user, so no special care is needed.
Extern template is used for example for @ref debugoperators "debug operators" Extern template is used for example for @ref debugoperators "debug operators"

2
doc/mainpage.dox

@ -27,7 +27,7 @@ namespace Magnum {
%Magnum is 2D/3D graphics engine written in C++11 and modern OpenGL. Its goal %Magnum is 2D/3D graphics engine written in C++11 and modern OpenGL. Its goal
is to simplify low-level graphics development and interaction with OpenGL using is to simplify low-level graphics development and interaction with OpenGL using
recent C++11 features and abstract away platform-specific issues. recent C++11 features and to abstract away platform-specific issues.
@section mainpage-design-goals Design goals @section mainpage-design-goals Design goals

180
doc/matrix-vector.dox

@ -22,7 +22,7 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
namespace Magnum { namespace Math { namespace Magnum {
/** @page matrix-vector Operations with matrices and vectors /** @page matrix-vector Operations with matrices and vectors
@brief Introduction to essential classes of the graphics pipeline. @brief Introduction to essential classes of the graphics pipeline.
@ -36,68 +36,79 @@ easier.
@section matrix-vector-hierarchy Matrix and vector classes @section matrix-vector-hierarchy Matrix and vector classes
%Magnum has three main matrix and vector classes: RectangularMatrix, (square) %Magnum has three main matrix and vector classes: @ref Math::RectangularMatrix,
Matrix and Vector. To achieve greatest code reuse, %Matrix is internally (square) @ref Math::Matrix and @ref Math::Vector. To achieve greatest code
square %RectangularMatrix and %RectangularMatrix is internally array of one or reuse, %Matrix is internally square %RectangularMatrix and %RectangularMatrix
more %Vector instances. Both vectors and matrices can have arbitrary size is internally array of one or more %Vector instances. Both vectors and matrices
(known at compile time) and can store any arithmetic type. 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 Each subclass brings some specialization to its superclass and for most common
vector and matrix sizes there are specialized classes Matrix3 and Matrix4, vector and matrix sizes there are specialized classes @ref Math::Matrix3 and
implementing various transformation in 2D and 3D, Vector2, Vector3 and Vector4, @ref Math::Matrix4, implementing various transformations in 2D and 3D,
implementing direct access to named components. Functions of each class try to @ref Math::Vector2, @ref Math::Vector3 and @ref Math::Vector4, implementing
return the most specialized type known to make subsequent operations more direct access to named components. Functions of each class try to return the
convenient - columns of %RectangularMatrix are returned as %Vector, but when most specialized type known to make subsequent operations more convenient --
accessing columns of e.g. %Matrix3, they are returned as %Vector3. 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. Color3 and Color4 for There are also even more specialized subclasses, e.g. @ref Color3 and
color handling and conversion. @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 @section matrix-vector-construction Constructing matrices and vectors
Default constructors of RectangularMatrix and Vector (and Vector2, Vector3, Default constructors of @ref Math::RectangularMatrix and @ref Math::Vector (and
Vector4, Color3) create zero-filled objects. Matrix (and Matrix3, Matrix4) is @ref Math::Vector2, @ref Math::Vector3, @ref Math::Vector4, @ref Color3) create
by default constructed as identity matrix. Color4 has alpha value set to opaque. 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 @code
RectangularMatrix<2, 3, Int> a; // zero-filled Matrix2x3 a; // zero-filled
Vector<3, Int> b; // zero-filled Vector3i b; // zero-filled
Matrix<3, Int> identity; // diagonal set to 1 Matrix3 identity; // diagonal set to 1
Matrix<3, Int> zero(Matrix<3, Int>::Zero); // zero-filled Matrix3 zero(Matrix::Zero); // zero-filled
Color4<Float> black1; // {0.0f, 0.0f, 0.0f, 1.0f} Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f}
Color4<unsigned char> black2; // {0, 0, 0, 255} BasicColor4<UnsignedByte> black2; // {0, 0, 0, 255}
@endcode @endcode
Most common and most efficient way to create vector is to pass all values to 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, matrix is created by passing all column vectors to the
constructor. constructor.
@code @code
Vector3<Int> vec(0, 1, 2); Vector3i vec(0, 1, 2);
Matrix3<Int> mat({0, 1, 2}, Matrix3 mat({0.0f, 1.9f, 2.2f},
{3, 4, 5}, {3.5f, 4.0f, 5.1f},
{6, 7, 8}); {6.0f, 7.3f, 8.0f});
@endcode @endcode
All constructors check number of passed arguments and the errors are catched All constructors check number of passed arguments and the errors are catched
at compile time. at compile time.
You can specify all components of vector or whole diagonal of square matrix at You can specify all components of vector or whole diagonal of square matrix at
once: once or you can create diagonal matrix from vector:
@code @code
Matrix3<Int> diag(Matrix3<Int>::Identity, 2); // diagonal set to 2, zeros elsewhere Matrix3 diag(Matrix3::Identity, 2.0f); // diagonal set to 2.0f, zeros elsewhere
Vector3<Int> fill(10); // {10, 10, 10} Vector3i fill(10); // {10, 10, 10}
auto diag2 = Matrix3::fromDiagonal({3.0f, 2.0f, 1.0f});
@endcode @endcode
It is possible to create matrices from other matrices and vectors with the It is possible to create matrices from other matrices and vectors with the same
same row count; vectors from vector and scalar: row count; vectors from vector and scalar:
@code @code
RectangularMatrix<2, 3, Int> a; Math::RectangularMatrix<2, 3, Int> a;
Vector3<Int> b, c; Math::Vector<3, Int> b, c;
Matrix3<Int> mat(a, b); Math::Matrix3<Int> mat(a, b);
Vector<8, Int> vec(1, b, 2, c); Math::Vector<8, Int> vec(1, b, 2, c);
@endcode @endcode
@todo Implement this ^ already.
It is also possible to create them from an C-style array. The function does 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 simple type cast without any copying, so it's possible to conveniently operate
on the array itself: on the array itself:
@ -111,8 +122,8 @@ array is long enough to contain all elements, so use with caution.
You can also *explicitly* convert between data types: You can also *explicitly* convert between data types:
@code @code
Vector4<Float> floating(1.3f, 2.7f, -15.0f, 7.0f); Vector4 floating(1.3f, 2.7f, -15.0f, 7.0f);
Vector4<Int> integral(floating); // {1, 2, -15, 7} auto integral = Vector4i(floating); // {1, 2, -15, 7}
@endcode @endcode
@section matrix-vector-component-access Accessing matrix and vector components @section matrix-vector-component-access Accessing matrix and vector components
@ -121,37 +132,98 @@ Column vectors of matrices and vector components can be accessed using square
brackets, there is also round bracket operator for accessing matrix components brackets, there is also round bracket operator for accessing matrix components
directly: directly:
@code @code
RectangularMatrix<3, 2, Int> a; Matrix3x2 a;
a[2] /= 2; // third column (column major indexing, see explanation below) a[2] /= 2.0f; // third column (column major indexing, see explanation below)
a[0][1] = 5; // first column, second element a[0][1] = 5.3f; // first column, second element
Vector<3, Int> b; Vector3i b;
b[1] = 1; // second element b[1] = 1; // second element
@endcode @endcode
Row vectors can be accessed too, but only for reading, and the access is slower 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): due to the way the matrix is stored (see explanation below):
@code @code
Vector<2, Int> c = a.row(2); // third row Vector2i c = a.row(2); // third row
@endcode @endcode
Fixed-size vector subclasses have functions for accessing named components Fixed-size vector subclasses have functions for accessing named components
and subparts: and subparts:
@code @code
Vector4<Int> a; Vector4i a;
Int x = a.x(); Int x = a.x();
a.y() += 5; a.y() += 5;
Vector3<Int> xyz = a.xyz(); Vector3i xyz = a.xyz();
xyz.xy() *= 5; xyz.xy() *= 5;
@endcode @endcode
Color3 and Color4 name their components `rgba` instead of `xyzw`. Color3 and Color4 name their components `rgba` instead of `xyzw`.
For more involved operations with components there is the swizzle() function: 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 @code
Vector<4, Int> original(-1, 2, 3, 4); BasicColor3<UnsignedByte> color(80, 116, 34);
Vector<4, Int> bgra = swizzle<'b', 'g', 'r', 'a'>(original); // { 3, 2, -1, 4 } BasicColor3<UnsignedByte> lighter = color*1.5f; // lighter = {120, 174, 51}
Vector<6, Int> w10xyz = swizzle<'w', '1', '0', 'x', 'y', 'z'>(original); // { 4, 1, 0, -1, 2, 3 }
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 @endcode
@section matrix-vector-column-major Matrices are column-major and vectors are columns @section matrix-vector-column-major Matrices are column-major and vectors are columns
@ -163,21 +235,21 @@ implications and it may differ from what is common in mathematics:
- Order of template arguments in specification of RectangularMatrix is also - Order of template arguments in specification of RectangularMatrix is also
column-major: column-major:
@code @code
RectangularMatrix<2, 3, Int> mat; // two columns, three rows Math::RectangularMatrix<2, 3, Int> mat; // two columns, three rows
@endcode @endcode
- Order of components in matrix constructors is also column-major, further - Order of components in matrix constructors is also column-major, further
emphasized by requirement that you have to pass directly column vectors: emphasized by requirement that you have to pass directly column vectors:
@code @code
Matrix3<Int> mat({0, 1, 2}, Math::Matrix3<Int> mat({0, 1, 2},
{3, 4, 5}, {3, 4, 5},
{6, 7, 8}); // first column is {0, 1, 2} {6, 7, 8}); // first column is {0, 1, 2}
@endcode @endcode
- Element accessing order is also column-major, thus the bracket operator is - Element accessing order is also column-major, thus the bracket operator is
accessing columns. Returned vector has also its own bracket operator, which accessing columns. Returned vector has also its own bracket operator, which
is then indexing rows. is then indexing rows.
@code @code
mat[0] *= 2; // first column mat[0] *= 2; // first column
mat[2][0] = 5; // first element of first column mat[2][0] = 5; // first element of third column
@endcode @endcode
- Various algorithms which commonly operate on matrix rows (such as - Various algorithms which commonly operate on matrix rows (such as
@ref Algorithms::gaussJordanInPlace() "Gauss-Jordan elimination") have faster @ref Algorithms::gaussJordanInPlace() "Gauss-Jordan elimination") have faster

53
doc/portability.dox

@ -46,7 +46,7 @@ If you include Magnum.h, you get these predefined macros:
Example usage: Example usage:
@code @code
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
Mesh::setPolygonMode(Mesh::PolygonMode::Lines); Renderer::setPolygonMode(Renderer::PolygonMode::Lines);
// draw mesh as wireframe... // draw mesh as wireframe...
#else #else
// use different mesh, as polygon mode is not supported in OpenGL ES... // use different mesh, as polygon mode is not supported in OpenGL ES...
@ -54,7 +54,7 @@ Mesh::setPolygonMode(Mesh::PolygonMode::Lines);
@endcode @endcode
Each feature is marked accordingly if it is not available in some targets. See Each feature is marked accordingly if it is not available in some targets. See
also @ref requires-gl and @ref requires-gles30. also @ref requires-gl, @ref requires-gles20 and @ref requires-gles30.
@section portability-compiler Compiler-specific code @section portability-compiler Compiler-specific code
@ -62,38 +62,39 @@ also @ref requires-gl and @ref requires-gles30.
possible. Many features from C++11 are used to simplify things and make them possible. Many features from C++11 are used to simplify things and make them
faster and more secure, but on the other hand it requires fairly recent faster and more secure, but on the other hand it requires fairly recent
compiler with good enough support of the new standard. Currently %Magnum is compiler with good enough support of the new standard. Currently %Magnum is
written with GCC 4.7 and Clang 3.1 in mind, but support for some other written with GCC 4.8 and Clang 3.1 in mind, but support for some other
compilers is also available and handled by Corrade library. See Corrade.h for compilers is also available and handled by Corrade library. See @ref Corrade.h
more information. for more information.
Each feature is marked accordingly if it is not available on some compilers, Each feature is marked accordingly if it is not available on some compilers,
see @ref SceneGraph::DrawableGroup3D for an example. It is up to you (or your see @ref SceneGraph::DrawableGroup3D for an example. It is up to you (or your
platform) which compiler your code will support, code written for GCC 4.7 will platform) which compiler your code will support, code written for e.g. GCC 4.6
work also on Magnum compiled with support for older compilers. will work also on Magnum compiled with support for newer compilers, although
newer compilers may catch errors that weren't spotted by earlier versions.
@section portability-extensions Extension-aware code @section portability-extensions Extension-aware code
Some functionality is depending on support of particular extension and thus Some functionality is depending on support of particular extension and thus
the decision cannot be made at compile time. Header Extensions.h contains list the decision cannot be made at compile time. Header @ref Extensions.h contains
of extensions, which you can pass to Context::isExtensionSupported() and list of extensions, which you can pass to @ref Context::isExtensionSupported()
decide based on that: and decide based on that:
@code @code
if(Context::instance()->isExtensionSupported<GL::ARB::geometry_shader4>()) { if(Context::instance()->isExtensionSupported<GL::ARB::geometry_shader4>()) {
// draw mesh with wireframe on top in one pass using geometry shader... // draw mesh with wireframe on top in one pass using geometry shader...
} else { } else {
// draw underlying mesh... // draw underlying mesh...
Mesh::setPolygonMode(Mesh::PolygonMode::Lines); Renderer::setPolygonMode(Renderer::PolygonMode::Lines);
// draw mesh as wirefreame in second pass... // draw mesh as wirefreame in second pass...
} }
@endcode @endcode
You can also decide on particular OpenGL version using Context::isVersionSupported(), You can also decide on particular OpenGL version using @ref Context::isVersionSupported(),
but remember that some features from that version might be available even if but remember that some features from that version might be available even if
the drivers don't expose that version. the drivers don't expose that version.
On the other hand, if you don't want to write fallback code for unsupported On the other hand, if you don't want to write fallback code for unsupported
extensions, you can use macros MAGNUM_ASSERT_EXTENSION_SUPPORTED() or extensions, you can use macros @ref MAGNUM_ASSERT_EXTENSION_SUPPORTED() or
MAGNUM_ASSERT_VERSION_SUPPORTED() to add mandatory requirement of given @ref MAGNUM_ASSERT_VERSION_SUPPORTED() to add mandatory requirement of given
extension or version: extension or version:
@code @code
MAGNUM_ASSERT_EXTENSION_SUPPORTED(GL::ARB::geometry_shader4); MAGNUM_ASSERT_EXTENSION_SUPPORTED(GL::ARB::geometry_shader4);
@ -103,7 +104,7 @@ MAGNUM_ASSERT_EXTENSION_SUPPORTED(GL::ARB::geometry_shader4);
Each class, function or enum value is marked accordingly if it needs specific Each class, function or enum value is marked accordingly if it needs specific
extension or specific OpenGL version. Various classes in %Magnum are taking extension or specific OpenGL version. Various classes in %Magnum are taking
advantage of some extensions and enable faster code paths if given extension is advantage of some extensions and enable faster code paths if given extension is
available, but also have proper fallback when it's not, for example available, but also have proper fallback when it's not, see for example
@ref AbstractShaderProgram-performance-optimization "AbstractShaderProgram", @ref AbstractShaderProgram-performance-optimization "AbstractShaderProgram",
@ref AbstractTexture-performance-optimization "AbstractTexture" or @ref AbstractTexture-performance-optimization "AbstractTexture" or
@ref Mesh-performance-optimization "Mesh". See also @ref required-extensions. @ref Mesh-performance-optimization "Mesh". See also @ref required-extensions.
@ -117,8 +118,8 @@ texture uniform locations, required precision qualifiers in OpenGL ES etc.
Shader class allows you to explicitly specify shader version and based on that Shader class allows you to explicitly specify shader version and based on that
you can decide on the syntax in your shader code. You can also use you can decide on the syntax in your shader code. You can also use
Context::supportedVersion() to conveniently select highest supported version @ref Context::supportedVersion() to conveniently select highest supported
from a list: version from a list:
@code @code
// MyShader.vert // MyShader.vert
#if __VERSION__ < 130 #if __VERSION__ < 130
@ -141,22 +142,22 @@ Version version = Context::instance()->supportedVersion({Version::GL430, Version
attachShader(Shader::fromFile(version, "MyShader.vert")); attachShader(Shader::fromFile(version, "MyShader.vert"));
@endcode @endcode
All shaders in Shaders namespace support desktop OpenGL starting from version All shaders in @ref Shaders namespace support desktop OpenGL starting from
2.1 and also OpenGL ES 2.0 and 3.0. Feel free to look into their sources to version 2.1 and also OpenGL ES 2.0 and 3.0. Feel free to look into their
see how portability is handled there. sources to see how portability is handled there.
@section portability-applications Platform-specific application support @section portability-applications Platform-specific application support
Your application might run on Windows box, on some embedded Linux or even in Your application might run on Windows box, on some embedded Linux or even in
browser - each platform has different requirements how to create entry point browser - each platform has different requirements how to create entry point
to the application, how to handle input events, how to create window and to the application, how to handle input events, how to create window and
OpenGL context etc. Namespace Platform contains base classes for applications OpenGL context etc. Namespace @ref Platform contains application base classes
which are abstracting out most of it for your convenience. which are abstracting out most of it for your convenience.
All the classes support limited form of static polymorphism, which means you All the classes support limited form of static polymorphism, which means you
can switch to another base class and probably don't need to change any other can just switch to another base class and in many cases you won't need to
code. It has its limitations, though - some toolkits don't support all keys, change any other code. It has its limitations, though - some toolkits don't
mouse movement events etc. support all keys, mouse movement events etc.
In most cases the entry point is classic `main()` function, but some platforms In most cases the entry point is classic `main()` function, but some platforms
(e.g. Native Client) have different requirements. To make things easier, entry (e.g. Native Client) have different requirements. To make things easier, entry
@ -174,8 +175,8 @@ variables.
Example application, which targets both embedded Linux (using plain X and EGL) Example application, which targets both embedded Linux (using plain X and EGL)
and desktop (using SDL2 toolkit). Thanks to static polymorphism most of the and desktop (using SDL2 toolkit). Thanks to static polymorphism most of the
functions will work on both without changes, the main difference will be in functions will work on both without changes, the main difference might (or
particular *Event class implementations: might not, depending what you use) be in particular event handlers:
@code @code
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
#include <Platform/Sdl2Application.h> #include <Platform/Sdl2Application.h>

4
src/AbstractResourceLoader.h

@ -162,7 +162,7 @@ template<class T> class AbstractResourceLoader {
/** @overload */ /** @overload */
template<class U> void set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { template<class U> void set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) {
set(key, new typename std::remove_cv<typename std::remove_reference<U>::type>::type(std::forward<U>(data)), state, policy); set(key, new typename std::decay<U>::type(std::forward<U>(data)), state, policy);
} }
/** /**
@ -177,7 +177,7 @@ template<class T> class AbstractResourceLoader {
/** @overload */ /** @overload */
template<class U> void set(ResourceKey key, U&& data) { template<class U> void set(ResourceKey key, U&& data) {
set(key, new typename std::remove_cv<typename std::remove_reference<U>::type>::type(std::forward<U>(data))); set(key, new typename std::decay<U>::type(std::forward<U>(data)));
} }
/** /**

24
src/AbstractTexture.cpp

@ -684,10 +684,8 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G
const ImageFormat format = imageFormatForInternalFormat(internalFormat); const ImageFormat format = imageFormatForInternalFormat(internalFormat);
const ImageType type = imageTypeForInternalFormat(internalFormat); const ImageType type = imageTypeForInternalFormat(internalFormat);
auto levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
(this->*image1DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); (this->*image1DImplementation)(target, level, internalFormat, Math::max(Math::Vector<1, GLsizei>(1), size >> level), format, type, nullptr);
levelSize = Math::max(Math::Vector<1, GLsizei>(1), levelSize/2);
} }
} }
@ -721,15 +719,12 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G
if(target == GL_TEXTURE_2D) if(target == GL_TEXTURE_2D)
#endif #endif
{ {
Vector2i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
(this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); (this->*image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr);
levelSize = Math::max(Vector2i(1), levelSize/2);
} }
/* Cube map additionally needs to specify all faces */ /* Cube map additionally needs to specify all faces */
} else if(target == GL_TEXTURE_CUBE_MAP) { } else if(target == GL_TEXTURE_CUBE_MAP) {
Vector2i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
const std::initializer_list<GLenum> faces = { const std::initializer_list<GLenum> faces = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
@ -740,17 +735,14 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
}; };
for(auto it = faces.begin(); it != faces.end(); ++it) for(auto it = faces.begin(); it != faces.end(); ++it)
(this->*image2DImplementation)(*it, level, internalFormat, levelSize, format, type, nullptr); (this->*image2DImplementation)(*it, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr);
levelSize = Math::max(Vector2i(1), levelSize/2);
} }
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
/* Array texture is not scaled in "layer" dimension */ /* Array texture is not scaled in "layer" dimension */
} else if(target == GL_TEXTURE_1D_ARRAY) { } else if(target == GL_TEXTURE_1D_ARRAY) {
Vector2i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
(this->*image2DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); (this->*image2DImplementation)(target, level, internalFormat, Math::max(Vector2i(1), size >> level), format, type, nullptr);
levelSize.x() = Math::max(1, levelSize.x()/2);
} }
#endif #endif
@ -789,10 +781,8 @@ void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei level
if(target == GL_TEXTURE_3D_OES) if(target == GL_TEXTURE_3D_OES)
#endif #endif
{ {
Vector3i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
(this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); (this->*image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr);
levelSize = Math::max(Vector3i(1), levelSize/2);
} }
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -804,10 +794,8 @@ void AbstractTexture::storageImplementationFallback(GLenum target, GLsizei level
else if(target == GL_TEXTURE_2D_ARRAY) else if(target == GL_TEXTURE_2D_ARRAY)
#endif #endif
{ {
Vector3i levelSize = size;
for(GLsizei level = 0; level != levels; ++level) { for(GLsizei level = 0; level != levels; ++level) {
(this->*image3DImplementation)(target, level, internalFormat, levelSize, format, type, nullptr); (this->*image3DImplementation)(target, level, internalFormat, Math::max(Vector3i(1), size >> level), format, type, nullptr);
levelSize.xy() = Math::max(Vector2i(1), levelSize.xy()/2);
} }
#endif #endif

2
src/Audio/Context.h

@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
/** @file /** @file Audio/Context.h
* @brief Class Magnum::Audio::Context * @brief Class Magnum::Audio::Context
*/ */

8
src/Color.h

@ -254,13 +254,13 @@ template<class T> class BasicColor3: public Math::Vector3<T> {
return Implementation::value<T>(*this); return Implementation::value<T>(*this);
} }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor3, 3) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, BasicColor3)
}; };
/** @brief Three-component (RGB) float color */ /** @brief Three-component (RGB) float color */
typedef BasicColor3<Float> Color3; typedef BasicColor3<Float> Color3;
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(BasicColor3, 3) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, BasicColor3)
/** /**
@brief Four-component (RGBA) color @brief Four-component (RGBA) color
@ -374,13 +374,13 @@ class BasicColor4: public Math::Vector4<T> {
return Implementation::value<T>(rgb()); return Implementation::value<T>(rgb());
} }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor4, 4) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, BasicColor4)
}; };
/** @brief Four-component (RGBA) float color */ /** @brief Four-component (RGBA) float color */
typedef BasicColor4<Float> Color4; typedef BasicColor4<Float> Color4;
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(BasicColor4, 4) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, BasicColor4)
/** @debugoperator{Magnum::BasicColor3} */ /** @debugoperator{Magnum::BasicColor3} */
template<class T> inline Debug operator<<(Debug debug, const BasicColor3<T>& value) { template<class T> inline Debug operator<<(Debug debug, const BasicColor3<T>& value) {

2
src/Context.h

@ -38,6 +38,8 @@
namespace Magnum { namespace Magnum {
/** @todoc Resolve conflict with Audio/Context.h (Doxygen doesn't list this file) */
namespace Implementation { namespace Implementation {
struct State; struct State;
} }

6
src/DimensionTraits.h

@ -55,6 +55,12 @@ template<UnsignedInt dimensions, class T> struct DimensionTraits {
#endif #endif
}; };
/**
@todo `using VectorTypeForDimension<dimensions, T> = typename DimensionTraits<dimensions, T>::VectorType`
etc. shortcuts when support for GCC 4.6 is dropped (similarly to what C++14
does with type traits)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
/* One dimension */ /* One dimension */
template<class T> struct DimensionTraits<1, T> { template<class T> struct DimensionTraits<1, T> {

25
src/Math/Matrix.h

@ -184,17 +184,7 @@ template<std::size_t size, class T> class Matrix: public RectangularMatrix<size,
#endif #endif
}; };
#ifndef DOXYGEN_GENERATING_OUTPUT MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix<size, T>)
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator*(U number, const Matrix<size, T>& matrix) {
return number*RectangularMatrix<size, size, T>(matrix);
}
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Matrix<size, T>>::type operator/(U number, const Matrix<size, T>& matrix) {
return number/RectangularMatrix<size, size, T>(matrix);
}
template<std::size_t size, class T> inline Matrix<size, T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) {
return RectangularMatrix<1, size, T>(vector)*matrix;
}
#endif
/** @debugoperator{Magnum::Math::Matrix} */ /** @debugoperator{Magnum::Math::Matrix} */
template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix<size, T>& value) { template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix<size, T>& value) {
@ -202,7 +192,7 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
} }
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Type, VectorType, size) \ #define MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(size, Type, VectorType) \
VectorType<T>& operator[](std::size_t col) { \ VectorType<T>& operator[](std::size_t col) { \
return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \ return static_cast<VectorType<T>&>(Matrix<size, T>::operator[](col)); \
} \ } \
@ -229,17 +219,6 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
return Matrix<size, T>::invertedOrthogonal(); \ return Matrix<size, T>::invertedOrthogonal(); \
} }
#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& matrix) { \
return number*Matrix<size, T>(matrix); \
} \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number, const Type<T>& matrix) { \
return number/Matrix<size, T>(matrix); \
} \
template<class T> inline Type<T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return RectangularMatrix<1, size, T>(vector)*matrix; \
}
namespace Implementation { namespace Implementation {
template<std::size_t size, class T> class MatrixDeterminant { template<std::size_t size, class T> class MatrixDeterminant {

4
src/Math/Matrix3.h

@ -315,10 +315,10 @@ template<class T> class Matrix3: public Matrix<3, T> {
} }
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3<T>) MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3<T>)
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix3, Vector3, 3) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(3, Matrix3, Vector3)
}; };
MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix3, 3) MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(3, Matrix3)
/** @debugoperator{Magnum::Math::Matrix3} */ /** @debugoperator{Magnum::Math::Matrix3} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3<T>& value) {

4
src/Math/Matrix4.h

@ -383,10 +383,10 @@ template<class T> class Matrix4: public Matrix<4, T> {
} }
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4<T>) MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4<T>)
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(Matrix4, Vector4, 4) MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(4, Matrix4, Vector4)
}; };
MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Matrix4, 4) MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(4, Matrix4)
/** @debugoperator{Magnum::Math::Matrix4} */ /** @debugoperator{Magnum::Math::Matrix4} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4<T>& value) {

102
src/Math/RectangularMatrix.h

@ -286,11 +286,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* \boldsymbol A_j = a \boldsymbol A_j * \boldsymbol A_j = a \boldsymbol A_j
* @f] * @f]
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT RectangularMatrix<cols, rows, T>& operator*=(T number) {
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator*=(U number) {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator*=(U number) {
#endif
for(std::size_t i = 0; i != cols; ++i) for(std::size_t i = 0; i != cols; ++i)
_data[i] *= number; _data[i] *= number;
@ -300,14 +296,10 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/** /**
* @brief Multiply matrix with number * @brief Multiply matrix with number
* *
* @see operator*=(U), operator*(U, const RectangularMatrix<cols, rows, T>&) * @see operator*=(T), operator*(T, const RectangularMatrix<cols, rows, T>&)
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT RectangularMatrix<cols, rows, T> operator*(T number) const {
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number) const { return RectangularMatrix<cols, rows, T>(*this) *= number;
#else
template<class U> RectangularMatrix<cols, rows, T> operator*(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)*=number;
} }
/** /**
@ -317,11 +309,7 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* \boldsymbol A_j = \frac{\boldsymbol A_j} a * \boldsymbol A_j = \frac{\boldsymbol A_j} a
* @f] * @f]
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT RectangularMatrix<cols, rows, T>& operator/=(T number) {
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>&>::type operator/=(U number) {
#else
template<class U> RectangularMatrix<cols, rows, T>& operator/=(U number) {
#endif
for(std::size_t i = 0; i != cols; ++i) for(std::size_t i = 0; i != cols; ++i)
_data[i] /= number; _data[i] /= number;
@ -331,14 +319,11 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/** /**
* @brief Divide matrix with number * @brief Divide matrix with number
* *
* @see operator/=(), operator/(U, const RectangularMatrix<cols, rows, T>&) * @see operator/=(T),
* operator/(T, const RectangularMatrix<cols, rows, T>&)
*/ */
#ifndef DOXYGEN_GENERATING_OUTPUT RectangularMatrix<cols, rows, T> operator/(T number) const {
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number) const { return RectangularMatrix<cols, rows, T>(*this) /= number;
#else
template<class U> RectangularMatrix<cols, rows, T> operator/(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)/=number;
} }
/** /**
@ -358,8 +343,8 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
* (\boldsymbol {Aa})_i = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol a_k * (\boldsymbol {Aa})_i = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol a_k
* @f] * @f]
*/ */
Vector<rows, T> operator*(const Vector<rows, T>& other) const { Vector<rows, T> operator*(const Vector<cols, T>& other) const {
return operator*(RectangularMatrix<1, rows, T>(other))[0]; return operator*(RectangularMatrix<1, cols, T>(other))[0];
} }
/** /**
@ -414,13 +399,16 @@ template<std::size_t cols, std::size_t rows, class T> class RectangularMatrix {
/** @relates RectangularMatrix /** @relates RectangularMatrix
@brief Multiply number with matrix @brief Multiply number with matrix
Same as RectangularMatrix::operator*(U) const. Same as RectangularMatrix::operator*(T) const.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator*(
template<std::size_t cols, std::size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) { #ifdef DOXYGEN_GENERATING_OUTPUT
#else T
template<std::size_t cols, std::size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) { #else
#endif typename std::common_type<T>::type
#endif
number, const RectangularMatrix<cols, rows, T>& matrix)
{
return matrix*number; return matrix*number;
} }
@ -430,13 +418,16 @@ template<std::size_t cols, std::size_t rows, class T, class U> inline typename s
The computation is done column-wise. @f[ The computation is done column-wise. @f[
\boldsymbol B_j = \frac a {\boldsymbol A_j} \boldsymbol B_j = \frac a {\boldsymbol A_j}
@f] @f]
@see RectangularMatrix::operator/(U) const @see RectangularMatrix::operator/(T) const
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator/(
template<std::size_t cols, std::size_t rows, class T, class U> inline RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) { #ifdef DOXYGEN_GENERATING_OUTPUT
#else T
template<std::size_t cols, std::size_t rows, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) { #else
#endif typename std::common_type<T>::type
#endif
number, const RectangularMatrix<cols, rows, T>& matrix)
{
RectangularMatrix<cols, rows, T> out; RectangularMatrix<cols, rows, T> out;
for(std::size_t i = 0; i != cols; ++i) for(std::size_t i = 0; i != cols; ++i)
@ -509,11 +500,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
return *reinterpret_cast<const __VA_ARGS__*>(data); \ return *reinterpret_cast<const __VA_ARGS__*>(data); \
} \ } \
\ \
__VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator=(other); \
return *this; \
} \
\
__VA_ARGS__ operator-() const { \ __VA_ARGS__ operator-() const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(); \ return Math::RectangularMatrix<cols, rows, T>::operator-(); \
} \ } \
@ -531,20 +517,42 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
__VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \ __VA_ARGS__ operator-(const Math::RectangularMatrix<cols, rows, T>& other) const { \
return Math::RectangularMatrix<cols, rows, T>::operator-(other); \ return Math::RectangularMatrix<cols, rows, T>::operator-(other); \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator*=(U number) { \ __VA_ARGS__& operator*=(T number) { \
Math::RectangularMatrix<cols, rows, T>::operator*=(number); \ Math::RectangularMatrix<cols, rows, T>::operator*=(number); \
return *this; \ return *this; \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator*(U number) const { \ __VA_ARGS__ operator*(T number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator*(number); \ return Math::RectangularMatrix<cols, rows, T>::operator*(number); \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__&>::type operator/=(U number) { \ __VA_ARGS__& operator/=(T number) { \
Math::RectangularMatrix<cols, rows, T>::operator/=(number); \ Math::RectangularMatrix<cols, rows, T>::operator/=(number); \
return *this; \ return *this; \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, __VA_ARGS__>::type operator/(U number) const { \ __VA_ARGS__ operator/(T number) const { \
return Math::RectangularMatrix<cols, rows, T>::operator/(number); \ return Math::RectangularMatrix<cols, rows, T>::operator/(number); \
} }
#define MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(...) \
template<std::size_t size, class T> inline __VA_ARGS__ operator*(typename std::common_type<T>::type number, const __VA_ARGS__& matrix) { \
return number*static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<std::size_t size, class T> inline __VA_ARGS__ operator/(typename std::common_type<T>::type number, const __VA_ARGS__& matrix) { \
return number/static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<std::size_t size, class T> inline __VA_ARGS__ operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return Math::RectangularMatrix<1, size, T>(vector)*matrix; \
}
#define MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class T> inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& matrix) { \
return number*static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<class T> inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& matrix) { \
return number/static_cast<const Math::RectangularMatrix<size, size, T>&>(matrix); \
} \
template<class T> inline Type<T> operator*(const Vector<size, T>& vector, const RectangularMatrix<size, 1, T>& matrix) { \
return Math::RectangularMatrix<1, size, T>(vector)*matrix; \
}
#endif #endif
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> RectangularMatrix<cols, rows, T>::fromDiagonal(const Vector<DiagonalSize, T>& diagonal) { template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> RectangularMatrix<cols, rows, T>::fromDiagonal(const Vector<DiagonalSize, T>& diagonal) {

63
src/Math/Test/MatrixTest.cpp

@ -75,6 +75,9 @@ class MatrixTest: public Corrade::TestSuite::Tester {
void inverted(); void inverted();
void invertedOrthogonal(); void invertedOrthogonal();
void subclassTypes();
void subclass();
void debug(); void debug();
void configuration(); void configuration();
}; };
@ -103,6 +106,10 @@ MatrixTest::MatrixTest() {
&MatrixTest::determinant, &MatrixTest::determinant,
&MatrixTest::inverted, &MatrixTest::inverted,
&MatrixTest::invertedOrthogonal, &MatrixTest::invertedOrthogonal,
&MatrixTest::subclassTypes,
&MatrixTest::subclass,
&MatrixTest::debug, &MatrixTest::debug,
&MatrixTest::configuration}); &MatrixTest::configuration});
} }
@ -293,6 +300,62 @@ void MatrixTest::invertedOrthogonal() {
CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted()); CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted());
} }
template<class T> class BasicVec2: public Math::Vector<2, T> {
public:
template<class ...U> BasicVec2(U&&... args): Math::Vector<2, T>{std::forward<U>(args)...} {}
};
template<class T> class BasicMat2: public Math::Matrix<2, T> {
public:
template<class ...U> BasicMat2(U&&... args): Math::Matrix<2, T>{std::forward<U>(args)...} {}
MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(2, BasicMat2, BasicVec2)
};
typedef BasicVec2<Float> Vec2;
typedef BasicMat2<Float> Mat2;
void MatrixTest::subclassTypes() {
const Mat2 c;
Mat2 a;
CORRADE_VERIFY((std::is_same<decltype(c[1]), const Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(a[1]), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(c.row(1)), Vec2>::value));
const Mat2 c2;
const Vec2 cv;
CORRADE_VERIFY((std::is_same<decltype(c*c2), Mat2>::value));
CORRADE_VERIFY((std::is_same<decltype(c*cv), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.transposed()), Mat2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.inverted()), Mat2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.invertedOrthogonal()), Mat2>::value));
}
void MatrixTest::subclass() {
const Mat2 a(Vec2(2.0f, 3.5f),
Vec2(3.0f, 1.0f));
Mat2 b(Vec2(2.0f, 3.5f),
Vec2(3.0f, 1.0f));
CORRADE_COMPARE(a[1], Vec2(3.0f, 1.0f));
CORRADE_COMPARE(b[1], Vec2(3.0f, 1.0f));
CORRADE_COMPARE(a.row(1), Vec2(3.5f, 1.0f));
CORRADE_COMPARE(a*b, Mat2(Vec2(14.5f, 10.5f),
Vec2(9.0f, 11.5f)));
CORRADE_COMPARE(a*Vec2(1.0f, 0.5f), Vec2(3.5f, 4.0f));
CORRADE_COMPARE(a.transposed(), Mat2(Vec2(2.0f, 3.0f),
Vec2(3.5f, 1.0f)));
Mat2 c(Vec2(Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f),
Vec2(-Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f));
CORRADE_COMPARE(c.inverted(), Mat2(Vec2(Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f),
Vec2(Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f)));
CORRADE_COMPARE(c.invertedOrthogonal(), Mat2(Vec2(Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f),
Vec2(Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f)));
}
void MatrixTest::debug() { void MatrixTest::debug() {
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f), Vector4(4.0f, 4.0f, 7.0f, 3.0f),

140
src/Math/Test/RectangularMatrixTest.cpp

@ -74,12 +74,16 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester {
void addSubtract(); void addSubtract();
void multiplyDivide(); void multiplyDivide();
void multiply(); void multiply();
void multiplyVector();
void transposed(); void transposed();
void diagonal(); void diagonal();
void vector(); void vector();
void subclassTypes();
void subclass();
void debug(); void debug();
void configuration(); void configuration();
}; };
@ -91,6 +95,11 @@ typedef RectangularMatrix<2, 2, Int> Matrix2i;
typedef Vector<4, Float> Vector4; typedef Vector<4, Float> Vector4;
typedef Vector<3, Float> Vector3; typedef Vector<3, Float> Vector3;
typedef Vector<2, Float> Vector2; typedef Vector<2, Float> Vector2;
typedef RectangularMatrix<4, 3, Int> Matrix4x3i;
typedef RectangularMatrix<3, 4, Int> Matrix3x4i;
typedef Vector<4, Int> Vector4i;
typedef Vector<3, Int> Vector3i;
typedef Vector<2, Int> Vector2i; typedef Vector<2, Int> Vector2i;
RectangularMatrixTest::RectangularMatrixTest() { RectangularMatrixTest::RectangularMatrixTest() {
@ -111,12 +120,16 @@ RectangularMatrixTest::RectangularMatrixTest() {
&RectangularMatrixTest::addSubtract, &RectangularMatrixTest::addSubtract,
&RectangularMatrixTest::multiplyDivide, &RectangularMatrixTest::multiplyDivide,
&RectangularMatrixTest::multiply, &RectangularMatrixTest::multiply,
&RectangularMatrixTest::multiplyVector,
&RectangularMatrixTest::transposed, &RectangularMatrixTest::transposed,
&RectangularMatrixTest::diagonal, &RectangularMatrixTest::diagonal,
&RectangularMatrixTest::vector, &RectangularMatrixTest::vector,
&RectangularMatrixTest::subclassTypes,
&RectangularMatrixTest::subclass,
&RectangularMatrixTest::debug, &RectangularMatrixTest::debug,
&RectangularMatrixTest::configuration}); &RectangularMatrixTest::configuration});
} }
@ -313,19 +326,12 @@ void RectangularMatrixTest::multiplyDivide() {
CORRADE_COMPARE(-1.5f*matrix, multiplied); CORRADE_COMPARE(-1.5f*matrix, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, matrix); CORRADE_COMPARE(multiplied/-1.5f, matrix);
Math::RectangularMatrix<1, 1, Byte> matrixChar(32);
Math::RectangularMatrix<1, 1, Byte> multipliedChar(-48);
CORRADE_COMPARE(matrixChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, matrixChar);
CORRADE_COMPARE(-1.5f*matrixChar, multipliedChar);
/* Divide vector with number and inverse */ /* Divide vector with number and inverse */
Matrix2 divisor(Vector2( 1.0f, 2.0f), Matrix2 divisor(Vector2( 1.0f, 2.0f),
Vector2(-4.0f, 8.0f)); Vector2(-4.0f, 8.0f));
Matrix2 result(Vector2( 1.0f, 0.5f), Matrix2 result(Vector2( 1.0f, 0.5f),
Vector2(-0.25f, 0.125f)); Vector2(-0.25f, 0.125f));
CORRADE_COMPARE(1.0f/divisor, result); CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, matrixChar);
} }
void RectangularMatrixTest::multiply() { void RectangularMatrixTest::multiply() {
@ -355,6 +361,22 @@ void RectangularMatrixTest::multiply() {
CORRADE_COMPARE(left*right, expected); CORRADE_COMPARE(left*right, expected);
} }
void RectangularMatrixTest::multiplyVector() {
Vector4i a(-5, 27, 10, 33);
RectangularMatrix<3, 1, Int> b(1, 2, 3);
CORRADE_COMPARE(a*b, Matrix3x4i(
Vector4i( -5, 27, 10, 33),
Vector4i(-10, 54, 20, 66),
Vector4i(-15, 81, 30, 99)
));
Matrix3x4i c(Vector4i(0, 4, 8, 12),
Vector4i(1, 5, 9, 13),
Vector4i(3, 7, 11, 15));
Vector3i d(2, -2, 3);
CORRADE_COMPARE(c*d, Vector4i(7, 19, 31, 43));
}
void RectangularMatrixTest::transposed() { void RectangularMatrixTest::transposed() {
Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f), Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f),
Vector3( 4.0f, 5.0f, 7.0f), Vector3( 4.0f, 5.0f, 7.0f),
@ -399,6 +421,110 @@ void RectangularMatrixTest::vector() {
CORRADE_COMPARE(Matrix4x3i::fromVector(b), a); CORRADE_COMPARE(Matrix4x3i::fromVector(b), a);
} }
template<std::size_t size, class T> class BasicMat: public Math::RectangularMatrix<size, size, T> {
public:
template<class ...U> BasicMat(U&&... args): Math::RectangularMatrix<size, size, T>{std::forward<U>(args)...} {}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, BasicMat<size, T>)
};
MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(BasicMat<size, T>)
template<class T> class BasicMat2x2: public BasicMat<2, T> {
public:
template<class ...U> BasicMat2x2(U&&... args): BasicMat<2, T>{std::forward<U>(args)...} {}
MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(2, 2, BasicMat2x2<T>)
};
MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(2, BasicMat2x2)
typedef BasicMat2x2<Float> Mat2x2;
void RectangularMatrixTest::subclassTypes() {
Float* const data = nullptr;
const Float* const cdata = nullptr;
CORRADE_VERIFY((std::is_same<decltype(Mat2x2::from(data)), Mat2x2&>::value));
CORRADE_VERIFY((std::is_same<decltype(Mat2x2::from(cdata)), const Mat2x2&>::value));
/* Const operators */
const Mat2x2 c;
CORRADE_VERIFY((std::is_same<decltype(-c), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(c + c), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(c*1.0f), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f*c), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(c/1.0f), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f/c), Mat2x2>::value));
CORRADE_VERIFY((std::is_same<decltype(Vector2()*Math::RectangularMatrix<2, 1, Float>()), Mat2x2>::value));
/* Assignment operators */
Mat2x2 a;
CORRADE_VERIFY((std::is_same<decltype(a = c), Mat2x2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a += c), Mat2x2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a -= c), Mat2x2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a *= 1.0f), Mat2x2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a /= 1.0f), Mat2x2&>::value));
/* Operators on variable-sized matrix */
const BasicMat<3, Float> c2;
CORRADE_VERIFY((std::is_same<decltype(1.0f*c2), BasicMat<3, Float>>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f/c2), BasicMat<3, Float>>::value));
CORRADE_VERIFY((std::is_same<decltype(Vector3()*Math::RectangularMatrix<3, 1, Float>()), BasicMat<3, Float>>::value));
}
void RectangularMatrixTest::subclass() {
Float data[] = {1.0f, -2.0f, 3.0f, -4.5f};
CORRADE_COMPARE(Mat2x2::from(data), Mat2x2(Vector2(1.0f, -2.0f),
Vector2(3.0f, -4.5f)));
const Float cdata[] = {1.0f, -2.0f, 3.0f, -4.5f};
CORRADE_COMPARE(Mat2x2::from(cdata), Mat2x2(Vector2(1.0f, -2.0f),
Vector2(3.0f, -4.5f)));
const Mat2x2 a(Vector2(1.0f, -3.0f),
Vector2(-3.0f, 1.0f));
CORRADE_COMPARE(-a, Mat2x2(Vector2(-1.0f, 3.0f),
Vector2(3.0f, -1.0f)));
Mat2x2 b(Vector2(-2.0f, 5.0f),
Vector2(5.0f, -2.0f));
const Mat2x2 bExpected(Vector2(-1.0f, 2.0f),
Vector2(2.0f, -1.0f));
CORRADE_COMPARE(b + a, bExpected);
Mat2x2 c(Vector2(-2.0f, 5.0f),
Vector2(5.0f, -2.0f));
const Mat2x2 cExpected(Vector2(-3.0f, 8.0f),
Vector2(8.0f, -3.0f));
CORRADE_COMPARE(c - a, cExpected);
Mat2x2 d(Vector2(-2.0f, 5.0f),
Vector2(5.0f, -2.0f));
const Mat2x2 dExpected(Vector2(-4.0f, 10.0f),
Vector2(10.0f, -4.0f));
CORRADE_COMPARE(d*2.0f, dExpected);
CORRADE_COMPARE(2.0f*d, dExpected);
Mat2x2 e(Vector2(-2.0f, 5.0f),
Vector2(5.0f, -2.0f));
CORRADE_COMPARE(e/0.5f, dExpected);
CORRADE_COMPARE(2.0f/e, Mat2x2(Vector2(-1.0f, 0.4f),
Vector2(0.4f, -1.0f)));
const Vector2 f(2.0f, 5.0f);
const Math::RectangularMatrix<2, 1, Float> g(3.0f, -1.0f);
CORRADE_COMPARE(f*g, Mat2x2(Vector2(6.0f, 15.0f),
Vector2(-2.0f, -5.0f)));
/* Operators on variable-sized matrix */
const BasicMat<1, Float> h(-2.0f);
CORRADE_COMPARE(2.0f*h, (BasicMat<1, Float>(-4.0f)));
CORRADE_COMPARE(2.0f/h, (BasicMat<1, Float>(-1.0f)));
const Math::Vector<1, Float> i(2.0f);
const Math::RectangularMatrix<1, 1, Float> j(3.0f);
CORRADE_COMPARE(i*j, (BasicMat<1, Float>(6.0f)));
}
void RectangularMatrixTest::debug() { void RectangularMatrixTest::debug() {
Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f), Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.0f),
Vector4(4.0f, 4.0f, 7.0f, 3.0f), Vector4(4.0f, 4.0f, 7.0f, 3.0f),

180
src/Math/Test/VectorTest.cpp

@ -62,6 +62,7 @@ class VectorTest: public Corrade::TestSuite::Tester {
void constructConversion(); void constructConversion();
void constructCopy(); void constructCopy();
void isZero();
void isNormalized(); void isNormalized();
void convert(); void convert();
@ -70,7 +71,10 @@ class VectorTest: public Corrade::TestSuite::Tester {
void negative(); void negative();
void addSubtract(); void addSubtract();
void multiplyDivide(); void multiplyDivide();
void multiplyDivideIntegral();
void multiplyDivideComponentWise(); void multiplyDivideComponentWise();
void multiplyDivideComponentWiseIntegral();
void bitwise();
void compare(); void compare();
void compareComponentWise(); void compareComponentWise();
@ -91,6 +95,9 @@ class VectorTest: public Corrade::TestSuite::Tester {
void projectedOntoNormalized(); void projectedOntoNormalized();
void angle(); void angle();
void subclassTypes();
void subclass();
void debug(); void debug();
void configuration(); void configuration();
}; };
@ -109,6 +116,7 @@ VectorTest::VectorTest() {
&VectorTest::constructConversion, &VectorTest::constructConversion,
&VectorTest::constructCopy, &VectorTest::constructCopy,
&VectorTest::isZero,
&VectorTest::isNormalized, &VectorTest::isNormalized,
&VectorTest::convert, &VectorTest::convert,
@ -117,7 +125,10 @@ VectorTest::VectorTest() {
&VectorTest::negative, &VectorTest::negative,
&VectorTest::addSubtract, &VectorTest::addSubtract,
&VectorTest::multiplyDivide, &VectorTest::multiplyDivide,
&VectorTest::multiplyDivideIntegral,
&VectorTest::multiplyDivideComponentWise, &VectorTest::multiplyDivideComponentWise,
&VectorTest::multiplyDivideComponentWiseIntegral,
&VectorTest::bitwise,
&VectorTest::compare, &VectorTest::compare,
&VectorTest::compareComponentWise, &VectorTest::compareComponentWise,
@ -138,6 +149,9 @@ VectorTest::VectorTest() {
&VectorTest::projectedOntoNormalized, &VectorTest::projectedOntoNormalized,
&VectorTest::angle, &VectorTest::angle,
&VectorTest::subclassTypes,
&VectorTest::subclass,
&VectorTest::debug, &VectorTest::debug,
&VectorTest::configuration}); &VectorTest::configuration});
} }
@ -198,6 +212,11 @@ void VectorTest::constructCopy() {
CORRADE_COMPARE(b, Vector4(1.0f, 3.5f, 4.0f, -2.7f)); CORRADE_COMPARE(b, Vector4(1.0f, 3.5f, 4.0f, -2.7f));
} }
void VectorTest::isZero() {
CORRADE_VERIFY(!Vector3(0.01f, 0.0f, 0.0f).isZero());
CORRADE_VERIFY(Vector3(0.0f, 0.0f, 0.0f).isZero());
}
void VectorTest::isNormalized() { void VectorTest::isNormalized() {
CORRADE_VERIFY(!Vector3(1.0f, 2.0f, -1.0f).isNormalized()); CORRADE_VERIFY(!Vector3(1.0f, 2.0f, -1.0f).isNormalized());
CORRADE_VERIFY(Vector3(0.0f, 1.0f, 0.0f).isNormalized()); CORRADE_VERIFY(Vector3(0.0f, 1.0f, 0.0f).isNormalized());
@ -285,17 +304,21 @@ void VectorTest::multiplyDivide() {
CORRADE_COMPARE(-1.5f*vector, multiplied); CORRADE_COMPARE(-1.5f*vector, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vector); CORRADE_COMPARE(multiplied/-1.5f, vector);
Math::Vector<1, Byte> vectorChar(32); /* Divide vector with number and invert */
Math::Vector<1, Byte> multipliedChar(-48);
CORRADE_COMPARE(vectorChar*-1.5f, multipliedChar);
CORRADE_COMPARE(multipliedChar/-1.5f, vectorChar);
CORRADE_COMPARE(-1.5f*vectorChar, multipliedChar);
/* Divide vector with number and inverse */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f); Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f); Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
CORRADE_COMPARE(1.0f/divisor, result); CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, vectorChar); }
void VectorTest::multiplyDivideIntegral() {
Vector4i vector(32, 10, -6, 2);
Vector4i multiplied(-48, -15, 9, -3);
CORRADE_COMPARE(vector*-1.5f, multiplied);
CORRADE_COMPARE(-1.5f*vector, multiplied);
CORRADE_COMPARE(multiplied/-1.5f, vector);
/* Using integer vector as divisor is not supported */
} }
void VectorTest::multiplyDivideComponentWise() { void VectorTest::multiplyDivideComponentWise() {
@ -307,6 +330,33 @@ void VectorTest::multiplyDivideComponentWise() {
CORRADE_COMPARE(multiplied/multiplier, vec); CORRADE_COMPARE(multiplied/multiplier, vec);
} }
void VectorTest::multiplyDivideComponentWiseIntegral() {
Vector4i vec(7, 2, -16, -1);
Vector4 multiplier(2.0f, -1.5f, 0.5f, 10.0f);
Vector4i multiplied(14, -3, -8, -10);
CORRADE_COMPARE(vec*multiplier, multiplied);
CORRADE_COMPARE(multiplier*vec, multiplied);
CORRADE_COMPARE(multiplied/multiplier, vec);
/* Using integer vector as divisor is not supported */
}
void VectorTest::bitwise() {
typedef Math::Vector<2, Int> Vector2i;
const Vector2i a(85, 240);
const Vector2i b(170, 85);
CORRADE_COMPARE(~a, Vector2i(-86, -241));
CORRADE_COMPARE(a & b, Vector2i(0, 80));
CORRADE_COMPARE(a | b, Vector2i(255, 245));
CORRADE_COMPARE(a ^ b, Vector2i(255, 165));
const Vector2i c(7, 32);
CORRADE_COMPARE(c << 2, Vector2i(28, 128));
CORRADE_COMPARE(c >> 2, Vector2i(1, 8));
}
void VectorTest::dot() { void VectorTest::dot() {
CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f);
} }
@ -394,6 +444,120 @@ void VectorTest::angle() {
Rad(1.162514f)); Rad(1.162514f));
} }
template<class T> class BasicVec2: public Math::Vector<2, T> {
public:
template<class ...U> BasicVec2(U&&... args): Math::Vector<2, T>{std::forward<U>(args)...} {}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, BasicVec2)
};
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, BasicVec2)
typedef BasicVec2<Float> Vec2;
typedef BasicVec2<Int> Vec2i;
void VectorTest::subclassTypes() {
Float* const data = nullptr;
const Float* const cdata = nullptr;
CORRADE_VERIFY((std::is_same<decltype(Vec2::from(data)), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(Vec2::from(cdata)), const Vec2&>::value));
/* Const operators */
const Vec2 c;
const Vec2 c2;
CORRADE_VERIFY((std::is_same<decltype(-c), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c + c), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c*1.0f), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f*c), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c/1.0f), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f/c), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c*c2), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c/c2), Vec2>::value));
/* Assignment operators */
Vec2 a;
CORRADE_VERIFY((std::is_same<decltype(a = c), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a += c), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a -= c), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a *= 1.0f), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a /= 1.0f), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a *= c), Vec2&>::value));
CORRADE_VERIFY((std::is_same<decltype(a /= c), Vec2&>::value));
/* Bitwise operations */
const Vec2i ci;
Vec2i i;
CORRADE_VERIFY((std::is_same<decltype(~ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci & ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci | ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci ^ ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci << 1), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci >> 1), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(i &= ci), Vec2i&>::value));
CORRADE_VERIFY((std::is_same<decltype(i |= ci), Vec2i&>::value));
CORRADE_VERIFY((std::is_same<decltype(i ^= ci), Vec2i&>::value));
CORRADE_VERIFY((std::is_same<decltype(i <<= 1), Vec2i&>::value));
CORRADE_VERIFY((std::is_same<decltype(i >>= 1), Vec2i&>::value));
/* Integer multiplication/division */
CORRADE_VERIFY((std::is_same<decltype(ci*1.0f), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(1.0f*ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(c*ci), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci*c), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(ci/c), Vec2i>::value));
CORRADE_VERIFY((std::is_same<decltype(i *= c), Vec2i&>::value));
CORRADE_VERIFY((std::is_same<decltype(i /= c), Vec2i&>::value));
/* Functions */
CORRADE_VERIFY((std::is_same<decltype(c.normalized()), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.resized(1.0f)), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.projected(c2)), Vec2>::value));
CORRADE_VERIFY((std::is_same<decltype(c.projectedOntoNormalized(c2)), Vec2>::value));
}
void VectorTest::subclass() {
Float data[] = {1.0f, -2.0f};
CORRADE_COMPARE(Vec2::from(data), Vec2(1.0f, -2.0f));
const Float cdata[] = {1.0f, -2.0f};
CORRADE_COMPARE(Vec2::from(cdata), Vec2(1.0f, -2.0f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f) + Vec2(1.0f, -3.0f), Vec2(-1.0f, 2.0f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f) - Vec2(1.0f, -3.0f), Vec2(-3.0f, 8.0f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)*2.0f, Vec2(-4.0f, 10.0f));
CORRADE_COMPARE(2.0f*Vec2(-2.0f, 5.0f), Vec2(-4.0f, 10.0f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/0.5f, Vec2(-4.0f, 10.0f));
CORRADE_COMPARE(2.0f/Vec2(-2.0f, 5.0f), Vec2(-1.0f, 0.4f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)*Vec2(1.5f, -2.0f), Vec2(-3.0f, -10.0f));
CORRADE_COMPARE(Vec2(-2.0f, 5.0f)/Vec2(2.0f/3.0f, -0.5f), Vec2(-3.0f, -10.0f));
/* Bitwise operations */
CORRADE_COMPARE(~Vec2i(85, 240), Vec2i(-86, -241));
CORRADE_COMPARE(Vec2i(85, 240) & Vec2i(170, 85), Vec2i(0, 80));
CORRADE_COMPARE(Vec2i(85, 240) | Vec2i(170, 85), Vec2i(255, 245));
CORRADE_COMPARE(Vec2i(85, 240) ^ Vec2i(170, 85), Vec2i(255, 165));
CORRADE_COMPARE(Vec2i(7, 32) << 2, Vec2i(28, 128));
CORRADE_COMPARE(Vec2i(7, 32) >> 2, Vec2i(1, 8));
/* Integral multiplication/division */
CORRADE_COMPARE(Vec2i(2, 4)*1.5f, Vec2i(3, 6));
CORRADE_COMPARE(1.5f*Vec2i(2, 4), Vec2i(3, 6));
CORRADE_COMPARE(Vec2i(2, 4)/(2.0f/3.0f), Vec2i(3, 6));
CORRADE_COMPARE(Vec2i(2, 4)*Vec2(-1.5f, 0.5f), Vec2i(-3, 2));
CORRADE_COMPARE(Vec2(-1.5f, 0.5f)*Vec2i(2, 4), Vec2i(-3, 2));
CORRADE_COMPARE(Vec2i(2, 4)/Vec2(-2.0f/3.0f, 2.0f), Vec2i(-3, 2));
/* Functions */
CORRADE_COMPARE(Vec2(3.0f, 0.0f).normalized(), Vec2(1.0f, 0.0f));
CORRADE_COMPARE(Vec2(3.0f, 0.0f).resized(6.0f), Vec2(6.0f, 0.0f));
CORRADE_COMPARE(Vec2(1.0f, 1.0f).projected({0.0f, 2.0f}), Vec2(0.0f, 1.0f));
CORRADE_COMPARE(Vec2(1.0f, 1.0f).projectedOntoNormalized({0.0f, 1.0f}), Vec2(0.0f, 1.0f));
}
void VectorTest::debug() { void VectorTest::debug() {
std::ostringstream o; std::ostringstream o;
Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f); Debug(&o) << Vector4(0.5f, 15.0f, 1.0f, 1.0f);

16
src/Math/TypeTraits.h

@ -184,6 +184,14 @@ template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoi
constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; } constexpr static long double epsilon() { return LONG_DOUBLE_EQUALITY_PRECISION; }
}; };
namespace Implementation {
/* Proper comparison should be with epsilon^2, but the value is not
representable in given precision. Comparing to epsilon instead. */
template<class T> inline bool isZeroSquared(T lengthSquared) {
return std::abs(lengthSquared) < TypeTraits<T>::epsilon();
}
/* Comparing squared length to 1 is not sufficient to compare within range /* Comparing squared length to 1 is not sufficient to compare within range
[1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7 when [1 - epsilon, 1 + epsilon], as e.g. Quaternion with dot() = 1 + 1e-7 when
converted to matrix has column vectors with dot() = 1 + 1e-6, which is just converted to matrix has column vectors with dot() = 1 + 1e-6, which is just
@ -191,10 +199,10 @@ template<> struct TypeTraits<long double>: Implementation::TypeTraitsFloatingPoi
[1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2, [1 - epsilon, 1 + epsilon] or dot() in range [1 - 2*epsilon + epsilon^2,
1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision, 1 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */ it's omitted. */
namespace Implementation { template<class T> inline bool isNormalizedSquared(T lengthSquared) {
template<class T> inline bool isNormalizedSquared(T lengthSquared) { return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon(); }
}
} }
#endif #endif

585
src/Math/Vector.h

@ -230,6 +230,18 @@ template<std::size_t size, class T> class Vector {
/** @brief Component-wise greater than */ /** @brief Component-wise greater than */
BoolVector<size> operator>(const Vector<size, T>& other) const; BoolVector<size> operator>(const Vector<size, T>& other) const;
/**
* @brief Whether the vector is zero
*
* @f[
* |\boldsymbol a \cdot \boldsymbol a - 0| < \epsilon^2 \cong \epsilon
* @f]
* @see dot(), normalized()
*/
bool isZero() const {
return Implementation::isZeroSquared(dot());
}
/** /**
* @brief Whether the vector is normalized * @brief Whether the vector is normalized
* *
@ -304,12 +316,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[ * The computation is done in-place. @f[
* \boldsymbol a_i = b \boldsymbol a_i * \boldsymbol a_i = b \boldsymbol a_i
* @f] * @f]
* @see operator*=(const Vector<size, T>&),
* operator*=(Vector<size, Integral>&, FloatingPoint)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT Vector<size, T>& operator*=(T number) {
template<class U> Vector<size, T>& operator*=(U number) {
#else
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator*=(U number) {
#endif
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] *= number; _data[i] *= number;
@ -319,13 +329,11 @@ template<std::size_t size, class T> class Vector {
/** /**
* @brief Multiply vector with number * @brief Multiply vector with number
* *
* @see operator*=(U), operator*(U, const Vector<size, T>&) * @see operator*(const Vector<size, T>&) const,
* operator*=(T), operator*(T, const Vector<size, T>&),
* operator*(const Vector<size, Integral>&, FloatingPoint)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT Vector<size, T> operator*(T number) const {
template<class U> Vector<size, T> operator*(U number) const {
#else
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number) const {
#endif
return Vector<size, T>(*this) *= number; return Vector<size, T>(*this) *= number;
} }
@ -335,12 +343,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[ * The computation is done in-place. @f[
* \boldsymbol a_i = \frac{\boldsymbol a_i} b * \boldsymbol a_i = \frac{\boldsymbol a_i} b
* @f] * @f]
* @see operator/=(const Vector<size, T>&),
* operator/=(Vector<size, Integral>&, FloatingPoint)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT Vector<size, T>& operator/=(T number) {
template<class U> Vector<size, T>& operator/=(U number) {
#else
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>&>::type operator/=(U number) {
#endif
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] /= number; _data[i] /= number;
@ -350,13 +356,11 @@ template<std::size_t size, class T> class Vector {
/** /**
* @brief Divide vector with number * @brief Divide vector with number
* *
* @see operator/=(), operator/(U, const Vector<size, T>&) * @see operator/(const Vector<size, T>&) const,
* operator/=(T), operator/(T, const Vector<size, T>&),
* operator/(const Vector<size, Integral>&, FloatingPoint)
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT Vector<size, T> operator/(T number) const {
template<class U> Vector<size, T> operator/(U number) const {
#else
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number) const {
#endif
return Vector<size, T>(*this) /= number; return Vector<size, T>(*this) /= number;
} }
@ -366,8 +370,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[ * The computation is done in-place. @f[
* \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i * \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i
* @f] * @f]
* @see operator*=(T),
* operator*=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/ */
template<class U> Vector<size, T>& operator*=(const Vector<size, U>& other) { Vector<size, T>& operator*=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] *= other._data[i]; _data[i] *= other._data[i];
@ -377,9 +383,10 @@ template<std::size_t size, class T> class Vector {
/** /**
* @brief Multiply vector component-wise * @brief Multiply vector component-wise
* *
* @see operator*=(const Vector<size, U>&), product() * @see operator*(T) const, operator*=(const Vector<size, T>&),
* operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/ */
template<class U> Vector<size, T> operator*(const Vector<size, U>& other) const { Vector<size, T> operator*(const Vector<size, T>& other) const {
return Vector<size, T>(*this) *= other; return Vector<size, T>(*this) *= other;
} }
@ -389,8 +396,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[ * The computation is done in-place. @f[
* \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i} * \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i}
* @f] * @f]
* @see operator/=(T),
* operator/=(Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/ */
template<class U> Vector<size, T>& operator/=(const Vector<size, U>& other) { Vector<size, T>& operator/=(const Vector<size, T>& other) {
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
_data[i] /= other._data[i]; _data[i] /= other._data[i];
@ -400,9 +409,10 @@ template<std::size_t size, class T> class Vector {
/** /**
* @brief Divide vector component-wise * @brief Divide vector component-wise
* *
* @see operator/=(const Vector<size, U>&) * @see operator/(T) const, operator/=(const Vector<size, T>&),
* operator/(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&)
*/ */
template<class U> Vector<size, T> operator/(const Vector<size, U>& other) const { Vector<size, T> operator/(const Vector<size, T>& other) const {
return Vector<size, T>(*this) /= other; return Vector<size, T>(*this) /= other;
} }
@ -413,7 +423,7 @@ template<std::size_t size, class T> class Vector {
* other values, because it doesn't compute the square root. @f[ * other values, because it doesn't compute the square root. @f[
* \boldsymbol a \cdot \boldsymbol a = \sum_{i=0}^{n-1} \boldsymbol a_i^2 * \boldsymbol a \cdot \boldsymbol a = \sum_{i=0}^{n-1} \boldsymbol a_i^2
* @f] * @f]
* @see dot(const Vector&, const Vector&), isNormalized() * @see dot(const Vector<size, T>&, const Vector<size, T>&), isNormalized()
*/ */
T dot() const { return dot(*this, *this); } T dot() const { return dot(*this, *this); }
@ -495,7 +505,7 @@ template<std::size_t size, class T> class Vector {
/** /**
* @brief Product of values in the vector * @brief Product of values in the vector
* *
* @see operator*(const Vector&) * @see operator*(const Vector<size, T>&) const
*/ */
T product() const; T product() const;
@ -526,13 +536,16 @@ template<std::size_t size, class T> class Vector {
/** @relates Vector /** @relates Vector
@brief Multiply number with vector @brief Multiply number with vector
Same as Vector::operator*(U) const. Same as Vector::operator*(T) const.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT template<std::size_t size, class T> inline Vector<size, T> operator*(
template<std::size_t size, class T, class U> inline Vector<size, T> operator*(U number, const Vector<size, T>& vector) { #ifdef DOXYGEN_GENERATING_OUTPUT
#else T
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator*(U number, const Vector<size, T>& vector) { #else
#endif typename std::common_type<T>::type
#endif
number, const Vector<size, T>& vector)
{
return vector*number; return vector*number;
} }
@ -542,21 +555,406 @@ template<std::size_t size, class T, class U> inline typename std::enable_if<std:
@f[ @f[
\boldsymbol c_i = \frac b {\boldsymbol a_i} \boldsymbol c_i = \frac b {\boldsymbol a_i}
@f] @f]
@see Vector::operator/() @see Vector::operator/(T) const
*/ */
template<std::size_t size, class T> inline Vector<size, T> operator/(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
typename std::common_type<T>::type
#endif
number, const Vector<size, T>& vector)
{
Vector<size, T> out;
for(std::size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
return out;
}
/** @relates Vector
@brief Bitwise NOT of integral vector
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
template<std::size_t size, class T, class U> inline Vector<size, T> operator/(U number, const Vector<size, T>& vector) { Vector<size, Integral>
#else #else
template<std::size_t size, class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Vector<size, T>>::type operator/(U number, const Vector<size, T>& vector) { typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif #endif
Vector<size, T> out; operator~(const Vector<size, Integral>& vector) {
Vector<size, Integral> out;
for(std::size_t i = 0; i != size; ++i) for(std::size_t i = 0; i != size; ++i)
out[i] = number/vector[i]; out[i] = ~vector[i];
return out; return out;
} }
/** @relates Vector
@brief Do bitwise AND of two integral vectors and assign
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
#endif
operator&=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] &= b[i];
return a;
}
/** @relates Vector
@brief Bitwise AND of two integral vectors
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif
operator&(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy &= b;
}
/** @relates Vector
@brief Do bitwise OR of two integral vectors and assign
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
#endif
operator|=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] |= b[i];
return a;
}
/** @relates Vector
@brief Bitwise OR of two integral vectors
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif
operator|(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy |= b;
}
/** @relates Vector
@brief Do bitwise XOR of two integral vectors and assign
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
#endif
operator^=(Vector<size, Integral>& a, const Vector<size, Integral>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] ^= b[i];
return a;
}
/** @relates Vector
@brief Bitwise XOR of two integral vectors
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif
operator^(const Vector<size, Integral>& a, const Vector<size, Integral>& b) {
Vector<size, Integral> copy(a);
return copy ^= b;
}
/** @relates Vector
@brief Do bitwise left shift of integral vector and assign
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
#endif
operator<<=(Vector<size, Integral>& vector,
#ifdef DOXYGEN_GENERATING_OUTPUT
Integral
#else
typename std::common_type<Integral>::type
#endif
shift)
{
for(std::size_t i = 0; i != size; ++i)
vector[i] <<= shift;
return vector;
}
/** @relates Vector
@brief Bitwise left shift of integral vector
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif
operator<<(const Vector<size, Integral>& vector,
#ifdef DOXYGEN_GENERATING_OUTPUT
Integral
#else
typename std::common_type<Integral>::type
#endif
shift)
{
Vector<size, Integral> copy(vector);
return copy <<= shift;
}
/** @relates Vector
@brief Do bitwise right shift of integral vector and assign
The computation is done in-place.
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>&>::type
#endif
operator>>=(Vector<size, Integral>& vector,
#ifdef DOXYGEN_GENERATING_OUTPUT
Integral
#else
typename std::common_type<Integral>::type
#endif
shift) {
for(std::size_t i = 0; i != size; ++i)
vector[i] >>= shift;
return vector;
}
/** @relates Vector
@brief Bitwise left shift of integral vector
*/
template<std::size_t size, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value, Vector<size, Integral>>::type
#endif
operator>>(const Vector<size, Integral>& vector,
#ifdef DOXYGEN_GENERATING_OUTPUT
Integral
#else
typename std::common_type<Integral>::type
#endif
shift) {
Vector<size, Integral> copy(vector);
return copy >>= shift;
}
/** @relates Vector
@brief Multiply integral vector with floating-point number and assign
Similar to Vector::operator*=(T), except that the multiplication is done in
floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
#endif
operator*=(Vector<size, Integral>& vector, FloatingPoint number) {
for(std::size_t i = 0; i != size; ++i)
vector[i] *= number;
return vector;
}
/** @relates Vector
@brief Multiply integral vector with floating-point number
Similar to Vector::operator*(T) const, except that the multiplication is done
in floating-point.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator*(const Vector<size, Integral>& vector, FloatingPoint number) {
Vector<size, Integral> copy(vector);
return copy *= number;
}
/** @relates Vector
@brief Multiply floating-point number with integral vector
Same as operator*(const Vector<size, Integral>&, FloatingPoint).
*/
template<std::size_t size, class FloatingPoint, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator*(FloatingPoint number, const Vector<size, Integral>& vector) {
return vector*number;
}
/** @relates Vector
@brief Divide integral vector with floating-point number and assign
Similar to Vector::operator/=(T), except that the division is done in
floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
#endif
operator/=(Vector<size, Integral>& vector, FloatingPoint number) {
for(std::size_t i = 0; i != size; ++i)
vector[i] /= number;
return vector;
}
/** @relates Vector
@brief Divide integral vector with floating-point number
Similar to Vector::operator/(T) const, except that the division is done in
floating-point.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator/(const Vector<size, Integral>& vector, FloatingPoint number) {
Vector<size, Integral> copy(vector);
return copy /= number;
}
/** @relates Vector
@brief Multiply integral vector with floating-point vector component-wise and assign
Similar to Vector::operator*=(const Vector<size, T>&), except that the
multiplication is done in floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
#endif
operator*=(Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] *= b[i];
return a;
}
/** @relates Vector
@brief Multiply integral vector with floating-point vector component-wise
Similar to Vector::operator*(const Vector<size, T>&) const, except that the
multiplication is done in floating-point. The result is always integral vector,
convert both arguments to the same floating-point type to have floating-point
result.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator*(const Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
Vector<size, Integral> copy(a);
return copy *= b;
}
/** @relates Vector
@brief Multiply floating-point vector with integral vector component-wise
Same as operator*(const Vector<size, Integral>&, const Vector<size, FloatingPoint>&).
*/
template<std::size_t size, class FloatingPoint, class Integral> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator*(const Vector<size, FloatingPoint>& a, const Vector<size, Integral>& b) {
return b*a;
}
/** @relates Vector
@brief Divide integral vector with floating-point vector component-wise and assign
Similar to Vector::operator/=(const Vector<size, T>&), except that the division
is done in floating-point. The computation is done in-place.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>&
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>&>::type
#endif
operator/=(Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
for(std::size_t i = 0; i != size; ++i)
a[i] /= b[i];
return a;
}
/** @relates Vector
@brief Divide integral vector with floating-point vector component-wise
Similar to Vector::operator/(const Vector<size, T>&) const, except that the
division is done in floating-point. The result is always integral vector,
convert both arguments to the same floating-point type to have floating-point
result.
*/
template<std::size_t size, class Integral, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, Integral>
#else
typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Vector<size, Integral>>::type
#endif
operator/(const Vector<size, Integral>& a, const Vector<size, FloatingPoint>& b) {
Vector<size, Integral> copy(a);
return copy /= b;
}
/** @debugoperator{Magnum::Math::Vector} */ /** @debugoperator{Magnum::Math::Vector} */
template<std::size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector<size, T>& value) { template<std::size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector<size, T>& value) {
debug << "Vector("; debug << "Vector(";
@ -589,7 +987,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif #endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Type, size) \ #define MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(size, Type) \
constexpr static Type<T>& from(T* data) { \ constexpr static Type<T>& from(T* data) { \
return *reinterpret_cast<Type<T>*>(data); \ return *reinterpret_cast<Type<T>*>(data); \
} \ } \
@ -619,32 +1017,32 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
Type<T> operator-(const Math::Vector<size, T>& other) const { \ Type<T> operator-(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator-(other); \ return Math::Vector<size, T>::operator-(other); \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Type<T>&>::type operator*=(U number) { \ Type<T>& operator*=(T number) { \
Math::Vector<size, T>::operator*=(number); \ Math::Vector<size, T>::operator*=(number); \
return *this; \ return *this; \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number) const { \ Type<T> operator*(T number) const { \
return Math::Vector<size, T>::operator*(number); \ return Math::Vector<size, T>::operator*(number); \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Type<T>&>::type operator/=(U number) { \ Type<T>& operator/=(T number) { \
Math::Vector<size, T>::operator/=(number); \ Math::Vector<size, T>::operator/=(number); \
return *this; \ return *this; \
} \ } \
template<class U> typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number) const { \ Type<T> operator/(T number) const { \
return Math::Vector<size, T>::operator/(number); \ return Math::Vector<size, T>::operator/(number); \
} \ } \
template<class U> Type<T>& operator*=(const Math::Vector<size, U>& other) { \ Type<T>& operator*=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator*=(other); \ Math::Vector<size, T>::operator*=(other); \
return *this; \ return *this; \
} \ } \
template<class U> Type<T> operator*(const Math::Vector<size, U>& other) const { \ Type<T> operator*(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator*(other); \ return Math::Vector<size, T>::operator*(other); \
} \ } \
template<class U> Type<T>& operator/=(const Math::Vector<size, U>& other) { \ Type<T>& operator/=(const Math::Vector<size, T>& other) { \
Math::Vector<size, T>::operator/=(other); \ Math::Vector<size, T>::operator/=(other); \
return *this; \ return *this; \
} \ } \
template<class U> Type<T> operator/(const Math::Vector<size, U>& other) const { \ Type<T> operator/(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::operator/(other); \ return Math::Vector<size, T>::operator/(other); \
} \ } \
\ \
@ -656,14 +1054,91 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
} \ } \
Type<T> projected(const Math::Vector<size, T>& other) const { \ Type<T> projected(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projected(other); \ return Math::Vector<size, T>::projected(other); \
} \
Type<T> projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projectedOntoNormalized(other); \
} }
#define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ #define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator*(U number, const Type<T>& vector) { \ template<class T> inline Type<T> operator*(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number*Math::Vector<size, T>(vector); \ return number*static_cast<const Math::Vector<size, T>&>(vector); \
} \
template<class T> inline Type<T> operator/(typename std::common_type<T>::type number, const Type<T>& vector) { \
return number/static_cast<const Math::Vector<size, T>&>(vector); \
} \
\
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator~(const Type<Integral>& vector) { \
return ~static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator&=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) &= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator&(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) & b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator|=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) |= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator|(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) | b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator^=(Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) ^= b; \
return a; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator^(const Type<Integral>& a, const Math::Vector<size, Integral>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a) ^ b; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator<<=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) <<= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator<<(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) << shift; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>&>::type operator>>=(Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
static_cast<Math::Vector<size, Integral>&>(vector) >>= shift; \
return vector; \
} \
template<class Integral> inline typename std::enable_if<std::is_integral<Integral>::value, Type<Integral>>::type operator>>(const Type<Integral>& vector, typename std::common_type<Integral>::type shift) { \
return static_cast<const Math::Vector<size, Integral>&>(vector) >> shift; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) *= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)*number; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(FloatingPoint number, const Type<Integral>& vector) { \
return number*static_cast<const Math::Vector<size, Integral>&>(vector); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& vector, FloatingPoint number) { \
static_cast<Math::Vector<size, Integral>&>(vector) /= number; \
return vector; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& vector, FloatingPoint number) { \
return static_cast<const Math::Vector<size, Integral>&>(vector)/number; \
} \
\
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator*=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) *= b; \
return a; \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return static_cast<const Math::Vector<size, Integral>&>(a)*b; \
} \
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator*(const Math::Vector<size, FloatingPoint>& a, const Type<Integral>& b) { \
return a*static_cast<const Math::Vector<size, Integral>&>(b); \
} \
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>&>::type operator/=(Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
static_cast<Math::Vector<size, Integral>&>(a) /= b; \
return a; \
} \ } \
template<class T, class U> inline typename std::enable_if<std::is_arithmetic<U>::value, Type<T>>::type operator/(U number, const Type<T>& vector) { \ template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_integral<Integral>::value && std::is_floating_point<FloatingPoint>::value, Type<Integral>>::type operator/(const Type<Integral>& a, const Math::Vector<size, FloatingPoint>& b) { \
return number/Math::Vector<size, T>(vector); \ return static_cast<const Math::Vector<size, Integral>&>(a)/b; \
} }
#endif #endif

4
src/Math/Vector2.h

@ -138,10 +138,10 @@ template<class T> class Vector2: public Vector<2, T> {
*/ */
Vector2<T> perpendicular() const { return {-y(), x()}; } Vector2<T> perpendicular() const { return {-y(), x()}; }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector2, 2) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2)
}; };
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector2, 2) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, Vector2)
/** @debugoperator{Magnum::Math::Vector2} */ /** @debugoperator{Magnum::Math::Vector2} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector2<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector2<T>& value) {

4
src/Math/Vector3.h

@ -165,10 +165,10 @@ template<class T> class Vector3: public Vector<3, T> {
Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); } Vector2<T>& xy() { return Vector2<T>::from(Vector<3, T>::data()); }
constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */ constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, Vector3)
}; };
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector3, 3) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Vector3)
/** @debugoperator{Magnum::Math::Vector3} */ /** @debugoperator{Magnum::Math::Vector3} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector3<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector3<T>& value) {

4
src/Math/Vector4.h

@ -106,10 +106,10 @@ template<class T> class Vector4: public Vector<4, T> {
Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); } Vector2<T>& xy() { return Vector2<T>::from(Vector<4, T>::data()); }
constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */ constexpr const Vector2<T> xy() const { return {x(), y()}; } /**< @overload */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4) MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, Vector4)
}; };
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Vector4, 4) MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, Vector4)
/** @debugoperator{Magnum::Math::Vector4} */ /** @debugoperator{Magnum::Math::Vector4} */
template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector4<T>& value) { template<class T> inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector4<T>& value) {

6
src/ResourceManager.h

@ -315,7 +315,7 @@ template<class... Types> class ResourceManager: private Implementation::Resource
/** @overload */ /** @overload */
template<class U> ResourceManager<Types...>& set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { template<class U> ResourceManager<Types...>& set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) {
return set(key, new typename std::remove_cv<typename std::remove_reference<U>::type>::type(std::forward<U>(data)), state, policy); return set(key, new typename std::decay<U>::type(std::forward<U>(data)), state, policy);
} }
/** /**
@ -331,7 +331,7 @@ template<class... Types> class ResourceManager: private Implementation::Resource
/** @overload */ /** @overload */
template<class U> ResourceManager<Types...>& set(ResourceKey key, U&& data) { template<class U> ResourceManager<Types...>& set(ResourceKey key, U&& data) {
return set(key, new typename std::remove_cv<typename std::remove_reference<U>::type>::type(std::forward<U>(data))); return set(key, new typename std::decay<U>::type(std::forward<U>(data)));
} }
/** @brief Fallback for not found resources */ /** @brief Fallback for not found resources */
@ -355,7 +355,7 @@ template<class... Types> class ResourceManager: private Implementation::Resource
/** @overload */ /** @overload */
template<class U> ResourceManager<Types...>& setFallback(U&& data) { template<class U> ResourceManager<Types...>& setFallback(U&& data) {
return setFallback(new typename std::remove_cv<typename std::remove_reference<U>::type>::type(std::forward<U>(data))); return setFallback(new typename std::decay<U>::type(std::forward<U>(data)));
} }
/** /**

4
src/Shapes/AxisAlignedBox.h

@ -81,7 +81,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT AxisAlignedBox {
_max = max; _max = max;
} }
/** @brief Collision with point */ /** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const; bool operator%(const Point<dimensions>& other) const;
private: private:
@ -94,7 +94,7 @@ typedef AxisAlignedBox<2> AxisAlignedBox2D;
/** @brief Three-dimensional axis-aligned box */ /** @brief Three-dimensional axis-aligned box */
typedef AxisAlignedBox<3> AxisAlignedBox3D; typedef AxisAlignedBox<3> AxisAlignedBox3D;
/** @collisionoperator{Point,AxisAlignedBox} */ /** @collisionoccurenceoperator{Point,AxisAlignedBox} */
template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const AxisAlignedBox<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const AxisAlignedBox<dimensions>& b) { return b % a; }
}} }}

8
src/Shapes/Capsule.h

@ -89,10 +89,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT Capsule {
/** @brief Set radius */ /** @brief Set radius */
void setRadius(Float radius) { _radius = radius; } void setRadius(Float radius) { _radius = radius; }
/** @brief Collision with point */ /** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const; bool operator%(const Point<dimensions>& other) const;
/** @brief Collision with sphere */ /** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const; bool operator%(const Sphere<dimensions>& other) const;
private: private:
@ -106,10 +106,10 @@ typedef Capsule<2> Capsule2D;
/** @brief Three-dimensional capsule */ /** @brief Three-dimensional capsule */
typedef Capsule<3> Capsule3D; typedef Capsule<3> Capsule3D;
/** @collisionoperator{Point,Capsule} */ /** @collisionoccurenceoperator{Point,Capsule} */
template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Capsule<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Capsule<dimensions>& b) { return b % a; }
/** @collisionoperator{Sphere,Capsule} */ /** @collisionoccurenceoperator{Sphere,Capsule} */
template<UnsignedInt dimensions> inline bool operator%(const Sphere<dimensions>& a, const Capsule<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Sphere<dimensions>& a, const Capsule<dimensions>& b) { return b % a; }
}} }}

8
src/Shapes/Cylinder.h

@ -89,10 +89,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT Cylinder {
/** @brief Set radius */ /** @brief Set radius */
void setRadius(Float radius) { _radius = radius; } void setRadius(Float radius) { _radius = radius; }
/** @brief Collision with point */ /** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const; bool operator%(const Point<dimensions>& other) const;
/** @brief Collision with sphere */ /** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const; bool operator%(const Sphere<dimensions>& other) const;
private: private:
@ -106,10 +106,10 @@ typedef Cylinder<2> Cylinder2D;
/** @brief Infinite three-dimensional cylinder */ /** @brief Infinite three-dimensional cylinder */
typedef Cylinder<3> Cylinder3D; typedef Cylinder<3> Cylinder3D;
/** @collisionoperator{Point,Cylinder} */ /** @collisionoccurenceoperator{Point,Cylinder} */
template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Cylinder<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Cylinder<dimensions>& b) { return b % a; }
/** @collisionoperator{Sphere,Cylinder} */ /** @collisionoccurenceoperator{Sphere,Cylinder} */
template<UnsignedInt dimensions> inline bool operator%(const Sphere<dimensions>& a, const Cylinder<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Sphere<dimensions>& a, const Cylinder<dimensions>& b) { return b % a; }
}} }}

8
src/Shapes/Plane.h

@ -76,20 +76,20 @@ class MAGNUM_SHAPES_EXPORT Plane {
_normal = normal; _normal = normal;
} }
/** @brief Collision with line */ /** @brief %Collision occurence with line */
bool operator%(const Line3D& other) const; bool operator%(const Line3D& other) const;
/** @brief Collision with line segment */ /** @brief %Collision occurence with line segment */
bool operator%(const LineSegment3D& other) const; bool operator%(const LineSegment3D& other) const;
private: private:
Vector3 _position, _normal; Vector3 _position, _normal;
}; };
/** @collisionoperator{Line,Plane} */ /** @collisionoccurenceoperator{Line,Plane} */
inline bool operator%(const Line3D& a, const Plane& b) { return b % a; } inline bool operator%(const Line3D& a, const Plane& b) { return b % a; }
/** @collisionoperator{LineSegment,Plane} */ /** @collisionoccurenceoperator{LineSegment,Plane} */
inline bool operator%(const LineSegment3D& a, const Plane& b) { return b % a; } inline bool operator%(const LineSegment3D& a, const Plane& b) { return b % a; }

14
src/Shapes/Sphere.h

@ -79,16 +79,16 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT Sphere {
/** @brief Set radius */ /** @brief Set radius */
void setRadius(Float radius) { _radius = radius; } void setRadius(Float radius) { _radius = radius; }
/** @brief Collision with point */ /** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const; bool operator%(const Point<dimensions>& other) const;
/** @brief Collision with line */ /** @brief %Collision occurence with line */
bool operator%(const Line<dimensions>& other) const; bool operator%(const Line<dimensions>& other) const;
/** @brief Collision with line segment */ /** @brief %Collision occurence with line segment */
bool operator%(const LineSegment<dimensions>& other) const; bool operator%(const LineSegment<dimensions>& other) const;
/** @brief Collision with sphere */ /** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const; bool operator%(const Sphere<dimensions>& other) const;
private: private:
@ -102,13 +102,13 @@ typedef Sphere<2> Sphere2D;
/** @brief Three-dimensional sphere */ /** @brief Three-dimensional sphere */
typedef Sphere<3> Sphere3D; typedef Sphere<3> Sphere3D;
/** @collisionoperator{Point,Sphere} */ /** @collisionoccurenceoperator{Point,Sphere} */
template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Sphere<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Point<dimensions>& a, const Sphere<dimensions>& b) { return b % a; }
/** @collisionoperator{Line,Sphere} */ /** @collisionoccurenceoperator{Line,Sphere} */
template<UnsignedInt dimensions> inline bool operator%(const Line<dimensions>& a, const Sphere<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const Line<dimensions>& a, const Sphere<dimensions>& b) { return b % a; }
/** @collisionoperator{LineSegment,Sphere} */ /** @collisionoccurenceoperator{LineSegment,Sphere} */
template<UnsignedInt dimensions> inline bool operator%(const LineSegment<dimensions>& a, const Sphere<dimensions>& b) { return b % a; } template<UnsignedInt dimensions> inline bool operator%(const LineSegment<dimensions>& a, const Sphere<dimensions>& b) { return b % a; }
}} }}

2
src/Text/DistanceFieldGlyphCache.cpp

@ -42,7 +42,7 @@ DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, c
GlyphCache(Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ? GlyphCache(Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ?
TextureFormat::Red : TextureFormat::RGB, originalSize, size, Vector2i(radius)), TextureFormat::Red : TextureFormat::RGB, originalSize, size, Vector2i(radius)),
#endif #endif
scale(Vector2(size)/originalSize), radius(radius) scale(Vector2(size)/Vector2(originalSize)), radius(radius)
{ {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg); MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_rg);

4
src/TextureTools/DistanceField.cpp

@ -158,7 +158,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Rectanglei& rectan
DistanceFieldShader shader; DistanceFieldShader shader;
shader.setRadius(radius) shader.setRadius(radius)
.setScaling(Vector2(imageSize)/rectangle.size()) .setScaling(Vector2(imageSize)/Vector2(rectangle.size()))
.use(); .use();
input.bind(DistanceFieldShader::TextureLayer); input.bind(DistanceFieldShader::TextureLayer);
@ -169,7 +169,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Rectanglei& rectan
if(!Context::current()->isVersionSupported(Version::GLES300)) if(!Context::current()->isVersionSupported(Version::GLES300))
#endif #endif
{ {
shader.setImageSizeInverted(Vector2(1)/imageSize); shader.setImageSizeInverted(1.0f/Vector2(imageSize));
} }
Mesh mesh; Mesh mesh;

Loading…
Cancel
Save