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." \
"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." \
"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\"" \
"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>" \

2
README.md

@ -1,6 +1,6 @@
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
recent C++11 features and abstract away platform-specific issues.
recent C++11 features and to abstract away platform-specific issues.
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
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
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
Out-of-class operators for collision in Shapes namespace should be marked with
@c \@collisionoperator, e.g.:
Out-of-class operators for collision occurence in Shapes namespace should be
marked with @c \@collisionoccurenceoperator, e.g.:
@code
// @collisionoperator{Point,Sphere}
// @collisionoccurenceoperator{Point,Sphere}
inline bool operator%(const Point& a, const Sphere& b) { return b % a; }
@endcode
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
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
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
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
available, each namespace has its own:
- Math/Math.h
- Magnum.h
- DebugTools/DebugTools.h
- SceneGraph/SceneGraph.h
- Shaders/Shaders.h
- Shapes/Shapes.h
- Text/Text.h
- Trade/Trade.h
- @ref Math/Math.h
- @ref Magnum.h
- @ref DebugTools/DebugTools.h
- @ref SceneGraph/SceneGraph.h
- @ref Shaders/Shaders.h
- @ref Shapes/Shapes.h
- @ref Text/Text.h
- @ref Trade/Trade.h
@section compilation-speedup-templates Templates
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
or @ref Double data type. However, having templated classes and function usually
means that the compiler compiles the whole templated code again in each
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 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
library the duplicates are just thrown out, which is a waste of compilation
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
so-called *template implementation file*. Generally, all header files in
%Magnum have `*.h` extension and all source files have `*.cpp` extension.
Template implementation files have `*.hpp` extension (hinting that they are
something between `*.h` and `*.cpp` files).
Template implementation files have `*.hpp` extension, hinting that they are
something between `*.h` and `*.cpp` files.
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
using one template specialization in many places, the compiler performs
compilation of the same template specialization many times. Template
implementation files give you the ability to explicitly instantiate the
template only once in some dedicated source file. Then you can include just
compilation of the same template specialization many times, as said above.
Template implementation files give you the ability to explicitly instantiate
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.
Templated classes which have implementation files state in their documentation
all common specializations that are already compiled in the libraries. So,
unless the templated class is too generic or you need something special, you
don't have to mess with template implementation files at all. See
SceneGraph::Object or SceneGraph::AbstractCamera for an example.
Sometimes you however need to use your own specialization and that's why
template implementation files are included in the library. For example we want
to use @ref SceneGraph::Object "Object" from SceneGraph with
@ref SceneGraph::MatrixTransformation3D "MatrixTransformation3D" with
@ref Double as underlying type, because our scene will span the whole universe.
We include the implementation file in dedicated source file and explicitly
instantiate the template:
Templated classes having code in template implementation files state in their
documentation all common specializations that are already compiled in the
libraries. So, unless the templated class is too generic or you need something
special, you don't have to mess with template implementation files at all. See
@ref SceneGraph::Object or @ref SceneGraph::AbstractCamera for an example.
Sometimes, however, you need to use your own specialization and that's why
template implementation files are installed along with the library. For example
we want to use @ref SceneGraph::Object "Object" from @ref SceneGraph with
@ref SceneGraph::BasicMatrixTransformation3D "BasicMatrixTransformation3D" with
@ref Double instead of @ref Float as underlying type, because our scene will
span the whole universe. We include the implementation file in dedicated source
file and explicitly instantiate the template:
@code
// Object.cpp
#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
All other files using the same object specialization now need to include only
SceneGraph/Object.h header. Thus the Object specialization will be compiled
only once in our `Object.cpp` file, saving precious compilation time.
@ref SceneGraph/Object.h header. Thus the @ref SceneGraph::Object "Object"
specialization will be compiled only once in our `Object.cpp` file, saving
precious compilation time.
@subsection compilation-speedup-extern-templates Extern templates
Keyword `extern template` is new thing in C++11, attempting to solve
compilation time problems. However, when used on whole classes, on some
compilers it causes conflicting symbol errors, so in %Magnum its used only for
specific functions.
Keyword `extern template` is a new thing in C++11, attempting to solve
compilation time problems related to templated code. However, on some compilers
it causes conflicting symbol errors when used on whole classes, thus in %Magnum
it's used only for specific functions.
This is completely transparent to end user, so no special care is needed.
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
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

180
doc/matrix-vector.dox

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

53
doc/portability.dox

@ -46,7 +46,7 @@ If you include Magnum.h, you get these predefined macros:
Example usage:
@code
#ifndef MAGNUM_TARGET_GLES
Mesh::setPolygonMode(Mesh::PolygonMode::Lines);
Renderer::setPolygonMode(Renderer::PolygonMode::Lines);
// draw mesh as wireframe...
#else
// use different mesh, as polygon mode is not supported in OpenGL ES...
@ -54,7 +54,7 @@ Mesh::setPolygonMode(Mesh::PolygonMode::Lines);
@endcode
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
@ -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
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
written with GCC 4.7 and Clang 3.1 in mind, but support for some other
compilers is also available and handled by Corrade library. See Corrade.h for
more information.
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 @ref Corrade.h
for more information.
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
platform) which compiler your code will support, code written for GCC 4.7 will
work also on Magnum compiled with support for older compilers.
platform) which compiler your code will support, code written for e.g. GCC 4.6
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
Some functionality is depending on support of particular extension and thus
the decision cannot be made at compile time. Header Extensions.h contains list
of extensions, which you can pass to Context::isExtensionSupported() and
decide based on that:
the decision cannot be made at compile time. Header @ref Extensions.h contains
list of extensions, which you can pass to @ref Context::isExtensionSupported()
and decide based on that:
@code
if(Context::instance()->isExtensionSupported<GL::ARB::geometry_shader4>()) {
// draw mesh with wireframe on top in one pass using geometry shader...
} else {
// draw underlying mesh...
Mesh::setPolygonMode(Mesh::PolygonMode::Lines);
Renderer::setPolygonMode(Renderer::PolygonMode::Lines);
// draw mesh as wirefreame in second pass...
}
@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
the drivers don't expose that version.
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
MAGNUM_ASSERT_VERSION_SUPPORTED() to add mandatory requirement of given
extensions, you can use macros @ref MAGNUM_ASSERT_EXTENSION_SUPPORTED() or
@ref MAGNUM_ASSERT_VERSION_SUPPORTED() to add mandatory requirement of given
extension or version:
@code
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
extension or specific OpenGL version. Various classes in %Magnum are taking
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 AbstractTexture-performance-optimization "AbstractTexture" or
@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
you can decide on the syntax in your shader code. You can also use
Context::supportedVersion() to conveniently select highest supported version
from a list:
@ref Context::supportedVersion() to conveniently select highest supported
version from a list:
@code
// MyShader.vert
#if __VERSION__ < 130
@ -141,22 +142,22 @@ Version version = Context::instance()->supportedVersion({Version::GL430, Version
attachShader(Shader::fromFile(version, "MyShader.vert"));
@endcode
All shaders in Shaders namespace support desktop OpenGL starting from version
2.1 and also OpenGL ES 2.0 and 3.0. Feel free to look into their sources to
see how portability is handled there.
All shaders in @ref Shaders namespace support desktop OpenGL starting from
version 2.1 and also OpenGL ES 2.0 and 3.0. Feel free to look into their
sources to see how portability is handled there.
@section portability-applications Platform-specific application support
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
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.
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
code. It has its limitations, though - some toolkits don't support all keys,
mouse movement events etc.
can just switch to another base class and in many cases you won't need to
change any other code. It has its limitations, though - some toolkits don't
support all keys, mouse movement events etc.
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
@ -174,8 +175,8 @@ variables.
Example application, which targets both embedded Linux (using plain X and EGL)
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
particular *Event class implementations:
functions will work on both without changes, the main difference might (or
might not, depending what you use) be in particular event handlers:
@code
#ifndef MAGNUM_TARGET_GLES
#include <Platform/Sdl2Application.h>

4
src/AbstractResourceLoader.h

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

2
src/Audio/Context.h

@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
*/
/** @file
/** @file Audio/Context.h
* @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);
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor3, 3)
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, BasicColor3)
};
/** @brief Three-component (RGB) float color */
typedef BasicColor3<Float> Color3;
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(BasicColor3, 3)
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, BasicColor3)
/**
@brief Four-component (RGBA) color
@ -374,13 +374,13 @@ class BasicColor4: public Math::Vector4<T> {
return Implementation::value<T>(rgb());
}
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor4, 4)
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, BasicColor4)
};
/** @brief Four-component (RGBA) float color */
typedef BasicColor4<Float> Color4;
MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(BasicColor4, 4)
MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, BasicColor4)
/** @debugoperator{Magnum::BasicColor3} */
template<class T> inline Debug operator<<(Debug debug, const BasicColor3<T>& value) {

2
src/Context.h

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

6
src/DimensionTraits.h

@ -55,6 +55,12 @@ template<UnsignedInt dimensions, class T> struct DimensionTraits {
#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
/* One dimension */
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
};
#ifndef DOXYGEN_GENERATING_OUTPUT
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
MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix<size, T>)
/** @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) {
@ -202,7 +192,7 @@ template<std::size_t size, class T> inline Corrade::Utility::Debug operator<<(Co
}
#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) { \
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(); \
}
#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 {
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_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} */
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_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} */
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
* @f]
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
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
RectangularMatrix<cols, rows, T>& operator*=(T number) {
for(std::size_t i = 0; i != cols; ++i)
_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
*
* @see operator*=(U), operator*(U, const RectangularMatrix<cols, rows, T>&)
* @see operator*=(T), operator*(T, const RectangularMatrix<cols, rows, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator*(U number) const {
#else
template<class U> RectangularMatrix<cols, rows, T> operator*(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)*=number;
RectangularMatrix<cols, rows, T> operator*(T number) const {
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
* @f]
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
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
RectangularMatrix<cols, rows, T>& operator/=(T number) {
for(std::size_t i = 0; i != cols; ++i)
_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
*
* @see operator/=(), operator/(U, const RectangularMatrix<cols, rows, T>&)
* @see operator/=(T),
* operator/(T, const RectangularMatrix<cols, rows, T>&)
*/
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class U> inline typename std::enable_if<std::is_arithmetic<U>::value, RectangularMatrix<cols, rows, T>>::type operator/(U number) const {
#else
template<class U> RectangularMatrix<cols, rows, T> operator/(U number) const {
#endif
return RectangularMatrix<cols, rows, T>(*this)/=number;
RectangularMatrix<cols, rows, T> operator/(T number) const {
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
* @f]
*/
Vector<rows, T> operator*(const Vector<rows, T>& other) const {
return operator*(RectangularMatrix<1, rows, T>(other))[0];
Vector<rows, T> operator*(const Vector<cols, T>& other) const {
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
@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, class U> inline RectangularMatrix<cols, rows, T> operator*(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
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) {
#endif
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator*(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
typename std::common_type<T>::type
#endif
number, const RectangularMatrix<cols, rows, T>& matrix)
{
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[
\boldsymbol B_j = \frac a {\boldsymbol A_j}
@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, class U> inline RectangularMatrix<cols, rows, T> operator/(U number, const RectangularMatrix<cols, rows, T>& matrix) {
#else
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) {
#endif
template<std::size_t cols, std::size_t rows, class T> inline RectangularMatrix<cols, rows, T> operator/(
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
typename std::common_type<T>::type
#endif
number, const RectangularMatrix<cols, rows, T>& matrix)
{
RectangularMatrix<cols, rows, T> out;
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); \
} \
\
__VA_ARGS__& operator=(const Math::RectangularMatrix<cols, rows, T>& other) { \
Math::RectangularMatrix<cols, rows, T>::operator=(other); \
return *this; \
} \
\
__VA_ARGS__ operator-() const { \
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 { \
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); \
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); \
} \
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); \
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); \
}
#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
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 invertedOrthogonal();
void subclassTypes();
void subclass();
void debug();
void configuration();
};
@ -103,6 +106,10 @@ MatrixTest::MatrixTest() {
&MatrixTest::determinant,
&MatrixTest::inverted,
&MatrixTest::invertedOrthogonal,
&MatrixTest::subclassTypes,
&MatrixTest::subclass,
&MatrixTest::debug,
&MatrixTest::configuration});
}
@ -293,6 +300,62 @@ void MatrixTest::invertedOrthogonal() {
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() {
Matrix4 m(Vector4(3.0f, 5.0f, 8.0f, 4.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 multiplyDivide();
void multiply();
void multiplyVector();
void transposed();
void diagonal();
void vector();
void subclassTypes();
void subclass();
void debug();
void configuration();
};
@ -91,6 +95,11 @@ typedef RectangularMatrix<2, 2, Int> Matrix2i;
typedef Vector<4, Float> Vector4;
typedef Vector<3, Float> Vector3;
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;
RectangularMatrixTest::RectangularMatrixTest() {
@ -111,12 +120,16 @@ RectangularMatrixTest::RectangularMatrixTest() {
&RectangularMatrixTest::addSubtract,
&RectangularMatrixTest::multiplyDivide,
&RectangularMatrixTest::multiply,
&RectangularMatrixTest::multiplyVector,
&RectangularMatrixTest::transposed,
&RectangularMatrixTest::diagonal,
&RectangularMatrixTest::vector,
&RectangularMatrixTest::subclassTypes,
&RectangularMatrixTest::subclass,
&RectangularMatrixTest::debug,
&RectangularMatrixTest::configuration});
}
@ -313,19 +326,12 @@ void RectangularMatrixTest::multiplyDivide() {
CORRADE_COMPARE(-1.5f*matrix, multiplied);
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 */
Matrix2 divisor(Vector2( 1.0f, 2.0f),
Vector2(-4.0f, 8.0f));
Matrix2 result(Vector2( 1.0f, 0.5f),
Vector2(-0.25f, 0.125f));
CORRADE_COMPARE(1.0f/divisor, result);
CORRADE_COMPARE(-1550.0f/multipliedChar, matrixChar);
}
void RectangularMatrixTest::multiply() {
@ -355,6 +361,22 @@ void RectangularMatrixTest::multiply() {
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() {
Matrix4x3 original(Vector3( 0.0f, 1.0f, 3.0f),
Vector3( 4.0f, 5.0f, 7.0f),
@ -399,6 +421,110 @@ void RectangularMatrixTest::vector() {
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() {
Matrix3x4 m(Vector4(3.0f, 5.0f, 8.0f, 4.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 constructCopy();
void isZero();
void isNormalized();
void convert();
@ -70,7 +71,10 @@ class VectorTest: public Corrade::TestSuite::Tester {
void negative();
void addSubtract();
void multiplyDivide();
void multiplyDivideIntegral();
void multiplyDivideComponentWise();
void multiplyDivideComponentWiseIntegral();
void bitwise();
void compare();
void compareComponentWise();
@ -91,6 +95,9 @@ class VectorTest: public Corrade::TestSuite::Tester {
void projectedOntoNormalized();
void angle();
void subclassTypes();
void subclass();
void debug();
void configuration();
};
@ -109,6 +116,7 @@ VectorTest::VectorTest() {
&VectorTest::constructConversion,
&VectorTest::constructCopy,
&VectorTest::isZero,
&VectorTest::isNormalized,
&VectorTest::convert,
@ -117,7 +125,10 @@ VectorTest::VectorTest() {
&VectorTest::negative,
&VectorTest::addSubtract,
&VectorTest::multiplyDivide,
&VectorTest::multiplyDivideIntegral,
&VectorTest::multiplyDivideComponentWise,
&VectorTest::multiplyDivideComponentWiseIntegral,
&VectorTest::bitwise,
&VectorTest::compare,
&VectorTest::compareComponentWise,
@ -138,6 +149,9 @@ VectorTest::VectorTest() {
&VectorTest::projectedOntoNormalized,
&VectorTest::angle,
&VectorTest::subclassTypes,
&VectorTest::subclass,
&VectorTest::debug,
&VectorTest::configuration});
}
@ -198,6 +212,11 @@ void VectorTest::constructCopy() {
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() {
CORRADE_VERIFY(!Vector3(1.0f, 2.0f, -1.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(multiplied/-1.5f, vector);
Math::Vector<1, Byte> vectorChar(32);
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 */
/* Divide vector with number and invert */
Vector4 divisor(1.0f, 2.0f, -4.0f, 8.0f);
Vector4 result(1.0f, 0.5f, -0.25f, 0.125f);
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() {
@ -307,6 +330,33 @@ void VectorTest::multiplyDivideComponentWise() {
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() {
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));
}
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() {
std::ostringstream o;
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; }
};
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
[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
@ -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 + 2*epsilon + epsilon^2]. Because epsilon^2 is way off machine precision,
it's omitted. */
namespace Implementation {
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}
template<class T> inline bool isNormalizedSquared(T lengthSquared) {
return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits<T>::epsilon();
}
}
#endif

585
src/Math/Vector.h

@ -230,6 +230,18 @@ template<std::size_t size, class T> class Vector {
/** @brief Component-wise greater than */
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
*
@ -304,12 +316,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[
* \boldsymbol a_i = b \boldsymbol a_i
* @f]
* @see operator*=(const Vector<size, T>&),
* operator*=(Vector<size, Integral>&, FloatingPoint)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
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
Vector<size, T>& operator*=(T number) {
for(std::size_t i = 0; i != size; ++i)
_data[i] *= number;
@ -319,13 +329,11 @@ template<std::size_t size, class T> class Vector {
/**
* @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
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
Vector<size, T> operator*(T number) const {
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[
* \boldsymbol a_i = \frac{\boldsymbol a_i} b
* @f]
* @see operator/=(const Vector<size, T>&),
* operator/=(Vector<size, Integral>&, FloatingPoint)
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
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
Vector<size, T>& operator/=(T number) {
for(std::size_t i = 0; i != size; ++i)
_data[i] /= number;
@ -350,13 +356,11 @@ template<std::size_t size, class T> class Vector {
/**
* @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
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
Vector<size, T> operator/(T number) const {
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[
* \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i
* @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)
_data[i] *= other._data[i];
@ -377,9 +383,10 @@ template<std::size_t size, class T> class Vector {
/**
* @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;
}
@ -389,8 +396,10 @@ template<std::size_t size, class T> class Vector {
* The computation is done in-place. @f[
* \boldsymbol a_i = \frac{\boldsymbol a_i}{\boldsymbol b_i}
* @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)
_data[i] /= other._data[i];
@ -400,9 +409,10 @@ template<std::size_t size, class T> class Vector {
/**
* @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;
}
@ -413,7 +423,7 @@ template<std::size_t size, class T> class Vector {
* 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
* @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); }
@ -495,7 +505,7 @@ template<std::size_t size, class T> class Vector {
/**
* @brief Product of values in the vector
*
* @see operator*(const Vector&)
* @see operator*(const Vector<size, T>&) const
*/
T product() const;
@ -526,13 +536,16 @@ template<std::size_t size, class T> class Vector {
/** @relates 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, class U> inline Vector<size, T> operator*(U number, const Vector<size, T>& vector) {
#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) {
#endif
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)
{
return vector*number;
}
@ -542,21 +555,406 @@ template<std::size_t size, class T, class U> inline typename std::enable_if<std:
@f[
\boldsymbol c_i = \frac b {\boldsymbol a_i}
@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
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
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
Vector<size, T> out;
operator~(const Vector<size, Integral>& vector) {
Vector<size, Integral> out;
for(std::size_t i = 0; i != size; ++i)
out[i] = number/vector[i];
out[i] = ~vector[i];
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} */
template<std::size_t size, class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector<size, T>& value) {
debug << "Vector(";
@ -589,7 +987,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
#endif
#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) { \
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 { \
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); \
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); \
} \
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); \
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); \
} \
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); \
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); \
} \
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); \
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); \
} \
\
@ -656,14 +1054,91 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit
} \
Type<T> projected(const Math::Vector<size, T>& other) const { \
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) \
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) { \
return number*Math::Vector<size, T>(vector); \
#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \
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 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) { \
return number/Math::Vector<size, 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 static_cast<const Math::Vector<size, Integral>&>(a)/b; \
}
#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()}; }
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} */
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()); }
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} */
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()); }
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} */
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 */
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 */
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 */
@ -355,7 +355,7 @@ template<class... Types> class ResourceManager: private Implementation::Resource
/** @overload */
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;
}
/** @brief Collision with point */
/** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const;
private:
@ -94,7 +94,7 @@ typedef AxisAlignedBox<2> AxisAlignedBox2D;
/** @brief Three-dimensional axis-aligned box */
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; }
}}

8
src/Shapes/Capsule.h

@ -89,10 +89,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT Capsule {
/** @brief Set radius */
void setRadius(Float radius) { _radius = radius; }
/** @brief Collision with point */
/** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const;
/** @brief Collision with sphere */
/** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const;
private:
@ -106,10 +106,10 @@ typedef Capsule<2> Capsule2D;
/** @brief Three-dimensional capsule */
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; }
/** @collisionoperator{Sphere,Capsule} */
/** @collisionoccurenceoperator{Sphere,Capsule} */
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 */
void setRadius(Float radius) { _radius = radius; }
/** @brief Collision with point */
/** @brief %Collision occurence with point */
bool operator%(const Point<dimensions>& other) const;
/** @brief Collision with sphere */
/** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const;
private:
@ -106,10 +106,10 @@ typedef Cylinder<2> Cylinder2D;
/** @brief Infinite three-dimensional cylinder */
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; }
/** @collisionoperator{Sphere,Cylinder} */
/** @collisionoccurenceoperator{Sphere,Cylinder} */
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;
}
/** @brief Collision with line */
/** @brief %Collision occurence with line */
bool operator%(const Line3D& other) const;
/** @brief Collision with line segment */
/** @brief %Collision occurence with line segment */
bool operator%(const LineSegment3D& other) const;
private:
Vector3 _position, _normal;
};
/** @collisionoperator{Line,Plane} */
/** @collisionoccurenceoperator{Line,Plane} */
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; }

14
src/Shapes/Sphere.h

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

2
src/Text/DistanceFieldGlyphCache.cpp

@ -42,7 +42,7 @@ DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, c
GlyphCache(Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ?
TextureFormat::Red : TextureFormat::RGB, originalSize, size, Vector2i(radius)),
#endif
scale(Vector2(size)/originalSize), radius(radius)
scale(Vector2(size)/Vector2(originalSize)), radius(radius)
{
#ifndef MAGNUM_TARGET_GLES
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;
shader.setRadius(radius)
.setScaling(Vector2(imageSize)/rectangle.size())
.setScaling(Vector2(imageSize)/Vector2(rectangle.size()))
.use();
input.bind(DistanceFieldShader::TextureLayer);
@ -169,7 +169,7 @@ void distanceField(Texture2D& input, Texture2D& output, const Rectanglei& rectan
if(!Context::current()->isVersionSupported(Version::GLES300))
#endif
{
shader.setImageSizeInverted(Vector2(1)/imageSize);
shader.setImageSizeInverted(1.0f/Vector2(imageSize));
}
Mesh mesh;

Loading…
Cancel
Save