From eb932381fcd178ea78525dc3f919ca2f7f8f749e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 30 Aug 2013 16:50:16 +0200 Subject: [PATCH 01/18] Minor documentation fixes. --- README.md | 2 +- doc/mainpage.dox | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 530a996e4..18fc6b706 100644 --- a/README.md +++ b/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 ============ diff --git a/doc/mainpage.dox b/doc/mainpage.dox index fe47ce03c..d24de7caf 100644 --- a/doc/mainpage.dox +++ b/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 From 5ff1020dcd4369ca701a666fb6bdc9c14be11969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 1 Sep 2013 17:14:12 +0200 Subject: [PATCH 02/18] Math: added Vector::isZero(). --- src/Math/Test/VectorTest.cpp | 7 +++++++ src/Math/TypeTraits.h | 16 ++++++++++++---- src/Math/Vector.h | 12 ++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 3b45e58da..c6aa1474c 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/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(); @@ -109,6 +110,7 @@ VectorTest::VectorTest() { &VectorTest::constructConversion, &VectorTest::constructCopy, + &VectorTest::isZero, &VectorTest::isNormalized, &VectorTest::convert, @@ -198,6 +200,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()); diff --git a/src/Math/TypeTraits.h b/src/Math/TypeTraits.h index 217e2275d..ce5708808 100644 --- a/src/Math/TypeTraits.h +++ b/src/Math/TypeTraits.h @@ -183,6 +183,14 @@ template<> struct TypeTraits: 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 inline bool isZeroSquared(T lengthSquared) { + return std::abs(lengthSquared) < TypeTraits::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 @@ -190,10 +198,10 @@ template<> struct TypeTraits: 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 inline bool isNormalizedSquared(T lengthSquared) { - return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits::epsilon(); - } +template inline bool isNormalizedSquared(T lengthSquared) { + return std::abs(lengthSquared - T(1)) < T(2)*TypeTraits::epsilon(); +} + } #endif diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 42aaac41c..b90923b92 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -220,6 +220,18 @@ template class Vector { /** @brief Component-wise greater than */ BoolVector operator>(const Vector& 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 * From d056a0be38fc66c59520815b170e4f7af2f67c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 1 Sep 2013 17:15:33 +0200 Subject: [PATCH 03/18] Added todo for the time when GCC 4.6 support is dropped. --- src/DimensionTraits.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/DimensionTraits.h b/src/DimensionTraits.h index 6ca6df1ad..69eb13a05 100644 --- a/src/DimensionTraits.h +++ b/src/DimensionTraits.h @@ -55,6 +55,12 @@ template struct DimensionTraits { #endif }; +/** +@todo `using VectorTypeForDimension = typename DimensionTraits::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 struct DimensionTraits<1, T> { From 91dc9f8956207791a54e47d162bbc9fd4a163c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 1 Sep 2013 20:08:50 +0200 Subject: [PATCH 04/18] std::decay in fact does the thing we need. Exactly this approach is used in e.g. std::make_optional, as seen on cppreference.com. Improves 68638969f3bbcd2f7f8a9a17619c1b1680146229. --- src/AbstractResourceLoader.h | 4 ++-- src/ResourceManager.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AbstractResourceLoader.h b/src/AbstractResourceLoader.h index 6100eddc9..892f13de3 100644 --- a/src/AbstractResourceLoader.h +++ b/src/AbstractResourceLoader.h @@ -162,7 +162,7 @@ template class AbstractResourceLoader { /** @overload */ template void set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { - set(key, new typename std::remove_cv::type>::type(std::forward(data)), state, policy); + set(key, new typename std::decay::type(std::forward(data)), state, policy); } /** @@ -177,7 +177,7 @@ template class AbstractResourceLoader { /** @overload */ template void set(ResourceKey key, U&& data) { - set(key, new typename std::remove_cv::type>::type(std::forward(data))); + set(key, new typename std::decay::type(std::forward(data))); } /** diff --git a/src/ResourceManager.h b/src/ResourceManager.h index 114983d6a..ab8c70659 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -315,7 +315,7 @@ template class ResourceManager: private Implementation::Resource /** @overload */ template ResourceManager& set(ResourceKey key, U&& data, ResourceDataState state, ResourcePolicy policy) { - return set(key, new typename std::remove_cv::type>::type(std::forward(data)), state, policy); + return set(key, new typename std::decay::type(std::forward(data)), state, policy); } /** @@ -331,7 +331,7 @@ template class ResourceManager: private Implementation::Resource /** @overload */ template ResourceManager& set(ResourceKey key, U&& data) { - return set(key, new typename std::remove_cv::type>::type(std::forward(data))); + return set(key, new typename std::decay::type(std::forward(data))); } /** @brief Fallback for not found resources */ @@ -355,7 +355,7 @@ template class ResourceManager: private Implementation::Resource /** @overload */ template ResourceManager& setFallback(U&& data) { - return setFallback(new typename std::remove_cv::type>::type(std::forward(data))); + return setFallback(new typename std::decay::type(std::forward(data))); } /** From ff0d6a2d3cc9b7d618b496d9fb9959fdada2335c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 00:06:49 +0200 Subject: [PATCH 05/18] Doc: reworded and improved compilation speedup page. --- doc/compilation-speedup.dox | 81 +++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/doc/compilation-speedup.dox b/doc/compilation-speedup.dox index efdd3db0a..1e87b8532 100644 --- a/doc/compilation-speedup.dox +++ b/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>; +template class SceneGraph::Object>; @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" From 346589732f474f147641c713aa93acf656459bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 00:24:36 +0200 Subject: [PATCH 06/18] Doc: updated portability page. --- doc/portability.dox | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/doc/portability.dox b/doc/portability.dox index 9c5031a6f..b8dc2971c 100644 --- a/doc/portability.dox +++ b/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()) { // 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 From 928104bb0a35578f5da4c5104d053282a892add3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 00:28:43 +0200 Subject: [PATCH 07/18] Failed attempt to resolve Doxygen file conflicts. Found even more stuff broken -- copied contents of Corrade::Utility::Directory::Flags into Magnum::Context::Flags (WTF!), asterisks in code listings... IS IT SO HARD TO FIX ONE THING AND DON'T BREAK THOUSAND OTHERS, DAMMIT?? --- src/Audio/Context.h | 2 +- src/Context.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Audio/Context.h b/src/Audio/Context.h index b28bba470..3969fb87b 100644 --- a/src/Audio/Context.h +++ b/src/Audio/Context.h @@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. */ -/** @file +/** @file Audio/Context.h * @brief Class Magnum::Audio::Context */ diff --git a/src/Context.h b/src/Context.h index b393b95f1..9e27df393 100644 --- a/src/Context.h +++ b/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; } From b4a33d15c3b17034a6111c3794a43594d8091638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:09:29 +0200 Subject: [PATCH 08/18] Math: improve integer/float Vector multiplication and division. Operators that are part of Vector are operating only with the same type as Vector itself, operators for multiplying/dividing integral vectors with floating-point numbers and vectors are now out-of-class and enabled only for integer vectors. It allows better control (e.g. multiplying integer and floating-point vector will _always_ result in floating-point one). Thoroughly tested integer/FP operations and also reworked and tested operator and funciton reimplementations in subclasses, both for value correctness and result type correctness. --- src/Color.h | 8 +- src/Math/Test/VectorTest.cpp | 134 ++++++++++- src/Math/Vector.h | 333 ++++++++++++++++++++++----- src/Math/Vector2.h | 4 +- src/Math/Vector3.h | 4 +- src/Math/Vector4.h | 4 +- src/Text/DistanceFieldGlyphCache.cpp | 2 +- src/TextureTools/DistanceField.cpp | 4 +- 8 files changed, 416 insertions(+), 77 deletions(-) diff --git a/src/Color.h b/src/Color.h index 410990944..a204e058d 100644 --- a/src/Color.h +++ b/src/Color.h @@ -254,13 +254,13 @@ template class BasicColor3: public Math::Vector3 { return Implementation::value(*this); } - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor3, 3) + MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(3, BasicColor3) }; /** @brief Three-component (RGB) float color */ typedef BasicColor3 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 { return Implementation::value(rgb()); } - MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(BasicColor4, 4) + MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(4, BasicColor4) }; /** @brief Four-component (RGBA) float color */ typedef BasicColor4 Color4; -MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(BasicColor4, 4) +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(4, BasicColor4) /** @debugoperator{Magnum::BasicColor3} */ template inline Debug operator<<(Debug debug, const BasicColor3& value) { diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index c6aa1474c..b6484e5e6 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -71,7 +71,9 @@ class VectorTest: public Corrade::TestSuite::Tester { void negative(); void addSubtract(); void multiplyDivide(); + void multiplyDivideIntegral(); void multiplyDivideComponentWise(); + void multiplyDivideComponentWiseIntegral(); void compare(); void compareComponentWise(); @@ -92,6 +94,9 @@ class VectorTest: public Corrade::TestSuite::Tester { void projectedOntoNormalized(); void angle(); + void subclassTypes(); + void subclass(); + void debug(); void configuration(); }; @@ -119,7 +124,9 @@ VectorTest::VectorTest() { &VectorTest::negative, &VectorTest::addSubtract, &VectorTest::multiplyDivide, + &VectorTest::multiplyDivideIntegral, &VectorTest::multiplyDivideComponentWise, + &VectorTest::multiplyDivideComponentWiseIntegral, &VectorTest::compare, &VectorTest::compareComponentWise, @@ -140,6 +147,9 @@ VectorTest::VectorTest() { &VectorTest::projectedOntoNormalized, &VectorTest::angle, + &VectorTest::subclassTypes, + &VectorTest::subclass, + &VectorTest::debug, &VectorTest::configuration}); } @@ -287,17 +297,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() { @@ -309,6 +323,18 @@ 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::dot() { CORRADE_COMPARE(Vector4::dot({1.0f, 0.5f, 0.75f, 1.5f}, {2.0f, 4.0f, 1.0f, 7.0f}), 15.25f); } @@ -396,6 +422,98 @@ void VectorTest::angle() { Rad(1.162514f)); } +template class BasicVec2: public Math::Vector<2, T> { + public: + template BasicVec2(U&&... args): Math::Vector<2, T>{std::forward(args)...} {} + + MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, BasicVec2) +}; + +MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(2, BasicVec2) + +typedef BasicVec2 Vec2; +typedef BasicVec2 Vec2i; + +void VectorTest::subclassTypes() { + Float* const data = nullptr; + const Float* const cdata = nullptr; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Const operators */ + const Vec2 c; + const Vec2 c2; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Assignment operators */ + Vec2 a; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Integer multiplication/division */ + const Vec2i ci; + Vec2i i; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Functions */ + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::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)); + + /* 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); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index b90923b92..28dc4daf8 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -306,12 +306,10 @@ template class Vector { * The computation is done in-place. @f[ * \boldsymbol a_i = b \boldsymbol a_i * @f] + * @see operator*=(const Vector&), + * operator*=(Vector&, FloatingPoint) */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector& operator*=(U number) { - #else - template typename std::enable_if::value, Vector&>::type operator*=(U number) { - #endif + Vector& operator*=(T number) { for(std::size_t i = 0; i != size; ++i) _data[i] *= number; @@ -321,13 +319,11 @@ template class Vector { /** * @brief Multiply vector with number * - * @see operator*=(U), operator*(U, const Vector&) + * @see operator*(const Vector&) const, + * operator*=(T), operator*(T, const Vector&), + * operator*(const Vector&, FloatingPoint) */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector operator*(U number) const { - #else - template typename std::enable_if::value, Vector>::type operator*(U number) const { - #endif + Vector operator*(T number) const { return Vector(*this) *= number; } @@ -337,12 +333,10 @@ template class Vector { * The computation is done in-place. @f[ * \boldsymbol a_i = \frac{\boldsymbol a_i} b * @f] + * @see operator/=(const Vector&), + * operator/=(Vector&, FloatingPoint) */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector& operator/=(U number) { - #else - template typename std::enable_if::value, Vector&>::type operator/=(U number) { - #endif + Vector& operator/=(T number) { for(std::size_t i = 0; i != size; ++i) _data[i] /= number; @@ -352,13 +346,11 @@ template class Vector { /** * @brief Divide vector with number * - * @see operator/=(), operator/(U, const Vector&) + * @see operator/(const Vector&) const, + * operator/=(T), operator/(T, const Vector&), + * operator/(const Vector&, FloatingPoint) */ - #ifdef DOXYGEN_GENERATING_OUTPUT - template Vector operator/(U number) const { - #else - template typename std::enable_if::value, Vector>::type operator/(U number) const { - #endif + Vector operator/(T number) const { return Vector(*this) /= number; } @@ -368,8 +360,10 @@ template class Vector { * The computation is done in-place. @f[ * \boldsymbol a_i = \boldsymbol a_i \boldsymbol b_i * @f] + * @see operator*=(T), + * operator*=(Vector&, const Vector&) */ - template Vector& operator*=(const Vector& other) { + Vector& operator*=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] *= other._data[i]; @@ -379,9 +373,10 @@ template class Vector { /** * @brief Multiply vector component-wise * - * @see operator*=(const Vector&), product() + * @see operator*(T) const, operator*=(const Vector&), + * operator*(const Vector&, const Vector&) */ - template Vector operator*(const Vector& other) const { + Vector operator*(const Vector& other) const { return Vector(*this) *= other; } @@ -391,8 +386,10 @@ template 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&, const Vector&) */ - template Vector& operator/=(const Vector& other) { + Vector& operator/=(const Vector& other) { for(std::size_t i = 0; i != size; ++i) _data[i] /= other._data[i]; @@ -402,9 +399,10 @@ template class Vector { /** * @brief Divide vector component-wise * - * @see operator/=(const Vector&) + * @see operator/(T) const, operator/=(const Vector&), + * operator/(const Vector&, const Vector&) */ - template Vector operator/(const Vector& other) const { + Vector operator/(const Vector& other) const { return Vector(*this) /= other; } @@ -415,7 +413,7 @@ template 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&, const Vector&), isNormalized() */ T dot() const { return dot(*this, *this); } @@ -497,7 +495,7 @@ template class Vector { /** * @brief Product of values in the vector * - * @see operator*(const Vector&) + * @see operator*(const Vector&) const */ T product() const; @@ -528,13 +526,16 @@ template 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 inline Vector operator*(U number, const Vector& vector) { -#else -template inline typename std::enable_if::value, Vector>::type operator*(U number, const Vector& vector) { -#endif +template inline Vector operator*( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const Vector& vector) +{ return vector*number; } @@ -544,13 +545,16 @@ template inline typename std::enable_if inline Vector operator/(U number, const Vector& vector) { -#else -template inline typename std::enable_if::value, Vector>::type operator/(U number, const Vector& vector) { -#endif +template inline Vector operator/( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const Vector& vector) +{ Vector out; for(std::size_t i = 0; i != size; ++i) @@ -559,6 +563,184 @@ template inline typename std::enable_if inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value && std::is_floating_point::value, Vector&>::type +#endif +operator*=(Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator*(const Vector& vector, FloatingPoint number) { + Vector copy(vector); + return copy *= number; +} + +/** @relates Vector +@brief Multiply floating-point number with integral vector + +Same as operator*(const Vector&, FloatingPoint). +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator*(FloatingPoint number, const Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value && std::is_floating_point::value, Vector&>::type +#endif +operator/=(Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator/(const Vector& vector, FloatingPoint number) { + Vector 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&), except that the +multiplication is done in floating-point. The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value && std::is_floating_point::value, Vector&>::type +#endif +operator*=(Vector& a, const Vector& 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&) 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator*(const Vector& a, const Vector& b) { + Vector copy(a); + return copy *= b; +} + +/** @relates Vector +@brief Multiply floating-point vector with integral vector component-wise + +Same as operator*(const Vector&, const Vector&). +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator*(const Vector& a, const Vector& b) { + return b*a; +} + +/** @relates Vector +@brief Divide integral vector with floating-point vector component-wise and assign + +Similar to Vector::operator/=(const Vector&), except that the division +is done in floating-point. The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value && std::is_floating_point::value, Vector&>::type +#endif +operator/=(Vector& a, const Vector& 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&) 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value && std::is_floating_point::value, Vector>::type +#endif +operator/(const Vector& a, const Vector& b) { + Vector copy(a); + return copy /= b; +} + /** @debugoperator{Magnum::Math::Vector} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector& value) { debug << "Vector("; @@ -591,7 +773,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& from(T* data) { \ return *reinterpret_cast*>(data); \ } \ @@ -621,32 +803,32 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit Type operator-(const Math::Vector& other) const { \ return Math::Vector::operator-(other); \ } \ - template typename std::enable_if::value, Type&>::type operator*=(U number) { \ + Type& operator*=(T number) { \ Math::Vector::operator*=(number); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator*(U number) const { \ + Type operator*(T number) const { \ return Math::Vector::operator*(number); \ } \ - template typename std::enable_if::value, Type&>::type operator/=(U number) { \ + Type& operator/=(T number) { \ Math::Vector::operator/=(number); \ return *this; \ } \ - template typename std::enable_if::value, Type>::type operator/(U number) const { \ + Type operator/(T number) const { \ return Math::Vector::operator/(number); \ } \ - template Type& operator*=(const Math::Vector& other) { \ + Type& operator*=(const Math::Vector& other) { \ Math::Vector::operator*=(other); \ return *this; \ } \ - template Type operator*(const Math::Vector& other) const { \ + Type operator*(const Math::Vector& other) const { \ return Math::Vector::operator*(other); \ } \ - template Type& operator/=(const Math::Vector& other) { \ + Type& operator/=(const Math::Vector& other) { \ Math::Vector::operator/=(other); \ return *this; \ } \ - template Type operator/(const Math::Vector& other) const { \ + Type operator/(const Math::Vector& other) const { \ return Math::Vector::operator/(other); \ } \ \ @@ -658,14 +840,53 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit } \ Type projected(const Math::Vector& other) const { \ return Math::Vector::projected(other); \ + } \ + Type projectedOntoNormalized(const Math::Vector& other) const { \ + return Math::Vector::projectedOntoNormalized(other); \ } -#define MAGNUM_VECTOR_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ - template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& vector) { \ - return number*Math::Vector(vector); \ +#define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ + template inline Type operator*(typename std::common_type::type number, const Type& vector) { \ + return number*static_cast&>(vector); \ + } \ + template inline Type operator/(typename std::common_type::type number, const Type& vector) { \ + return number/static_cast&>(vector); \ + } \ + \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& vector, FloatingPoint number) { \ + static_cast&>(vector) *= number; \ + return vector; \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& vector, FloatingPoint number) { \ + return static_cast&>(vector)*number; \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint number, const Type& vector) { \ + return number*static_cast&>(vector); \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& vector, FloatingPoint number) { \ + static_cast&>(vector) /= number; \ + return vector; \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& vector, FloatingPoint number) { \ + return static_cast&>(vector)/number; \ + } \ + \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& a, const Math::Vector& b) { \ + static_cast&>(a) *= b; \ + return a; \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& a, const Math::Vector& b) { \ + return static_cast&>(a)*b; \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Math::Vector& a, const Type& b) { \ + return a*static_cast&>(b); \ + } \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& a, const Math::Vector& b) { \ + static_cast&>(a) /= b; \ + return a; \ } \ - template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& vector) { \ - return number/Math::Vector(vector); \ + template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& a, const Math::Vector& b) { \ + return static_cast&>(a)/b; \ } #endif diff --git a/src/Math/Vector2.h b/src/Math/Vector2.h index 3f1b5a9dc..f55483b7d 100644 --- a/src/Math/Vector2.h +++ b/src/Math/Vector2.h @@ -134,10 +134,10 @@ template class Vector2: public Vector<2, T> { */ Vector2 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 inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector2& value) { diff --git a/src/Math/Vector3.h b/src/Math/Vector3.h index ad0beff03..99d0692f7 100644 --- a/src/Math/Vector3.h +++ b/src/Math/Vector3.h @@ -161,10 +161,10 @@ template class Vector3: public Vector<3, T> { Vector2& xy() { return Vector2::from(Vector<3, T>::data()); } constexpr const Vector2 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 inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector3& value) { diff --git a/src/Math/Vector4.h b/src/Math/Vector4.h index 2af6e2da8..ecc6cfe20 100644 --- a/src/Math/Vector4.h +++ b/src/Math/Vector4.h @@ -102,10 +102,10 @@ template class Vector4: public Vector<4, T> { Vector2& xy() { return Vector2::from(Vector<4, T>::data()); } constexpr const Vector2 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 inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Vector4& value) { diff --git a/src/Text/DistanceFieldGlyphCache.cpp b/src/Text/DistanceFieldGlyphCache.cpp index 476ee61b7..5b2eab84c 100644 --- a/src/Text/DistanceFieldGlyphCache.cpp +++ b/src/Text/DistanceFieldGlyphCache.cpp @@ -42,7 +42,7 @@ DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, c GlyphCache(Context::current()->isExtensionSupported() ? 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); diff --git a/src/TextureTools/DistanceField.cpp b/src/TextureTools/DistanceField.cpp index e2d185a8d..5165a3a51 100644 --- a/src/TextureTools/DistanceField.cpp +++ b/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; From 78417dfefad57ef331969f28ab6e3623fa6c4b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:19:42 +0200 Subject: [PATCH 09/18] Math: removed integer/float RectangularMatrix multiplication and division. We would need to duplicate all the functionality found in Vector, which I don't think is needed at all. If anyone needs to do this, it is possible to "linearize" the matrix into long vector and do the operations on it. Also updated subclass operator implementation, added tests for it, both for proper returned value and proper result type. --- src/Math/Matrix.h | 25 +---- src/Math/Matrix3.h | 4 +- src/Math/Matrix4.h | 4 +- src/Math/RectangularMatrix.h | 93 +++++++++++-------- src/Math/Test/RectangularMatrixTest.cpp | 117 ++++++++++++++++++++++-- 5 files changed, 169 insertions(+), 74 deletions(-) diff --git a/src/Math/Matrix.h b/src/Math/Matrix.h index e50272c9f..edcbaaf5c 100644 --- a/src/Math/Matrix.h +++ b/src/Math/Matrix.h @@ -180,17 +180,7 @@ template class Matrix: public RectangularMatrix inline typename std::enable_if::value, Matrix>::type operator*(U number, const Matrix& matrix) { - return number*RectangularMatrix(matrix); -} -template inline typename std::enable_if::value, Matrix>::type operator/(U number, const Matrix& matrix) { - return number/RectangularMatrix(matrix); -} -template inline Matrix operator*(const Vector& vector, const RectangularMatrix& matrix) { - return RectangularMatrix<1, size, T>(vector)*matrix; -} -#endif +MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(Matrix) /** @debugoperator{Magnum::Math::Matrix} */ template inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix& value) { @@ -198,7 +188,7 @@ template 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& operator[](std::size_t col) { \ return static_cast&>(Matrix::operator[](col)); \ } \ @@ -225,17 +215,6 @@ template inline Corrade::Utility::Debug operator<<(Co return Matrix::invertedOrthogonal(); \ } -#define MAGNUM_MATRIX_SUBCLASS_OPERATOR_IMPLEMENTATION(Type, size) \ - template inline typename std::enable_if::value, Type>::type operator*(U number, const Type& matrix) { \ - return number*Matrix(matrix); \ - } \ - template inline typename std::enable_if::value, Type>::type operator/(U number, const Type& matrix) { \ - return number/Matrix(matrix); \ - } \ - template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ - return RectangularMatrix<1, size, T>(vector)*matrix; \ - } - namespace Implementation { template class MatrixDeterminant { diff --git a/src/Math/Matrix3.h b/src/Math/Matrix3.h index d9d9b94b0..cbcc8e972 100644 --- a/src/Math/Matrix3.h +++ b/src/Math/Matrix3.h @@ -299,10 +299,10 @@ template class Matrix3: public Matrix<3, T> { } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(3, 3, Matrix3) - 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 inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix3& value) { diff --git a/src/Math/Matrix4.h b/src/Math/Matrix4.h index 3653f480f..12464fc9d 100644 --- a/src/Math/Matrix4.h +++ b/src/Math/Matrix4.h @@ -367,10 +367,10 @@ template class Matrix4: public Matrix<4, T> { } MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(4, 4, Matrix4) - 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 inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Matrix4& value) { diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 1079ef9a9..0b445cd60 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -271,11 +271,7 @@ template class RectangularMatrix { * \boldsymbol A_j = a \boldsymbol A_j * @f] */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator*=(U number) { - #else - template RectangularMatrix& operator*=(U number) { - #endif + RectangularMatrix& operator*=(T number) { for(std::size_t i = 0; i != cols; ++i) _data[i] *= number; @@ -285,14 +281,10 @@ template class RectangularMatrix { /** * @brief Multiply matrix with number * - * @see operator*=(U), operator*(U, const RectangularMatrix&) + * @see operator*=(T), operator*(T, const RectangularMatrix&) */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number) const { - #else - template RectangularMatrix operator*(U number) const { - #endif - return RectangularMatrix(*this)*=number; + RectangularMatrix operator*(T number) const { + return RectangularMatrix(*this) *= number; } /** @@ -302,11 +294,7 @@ template class RectangularMatrix { * \boldsymbol A_j = \frac{\boldsymbol A_j} a * @f] */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix&>::type operator/=(U number) { - #else - template RectangularMatrix& operator/=(U number) { - #endif + RectangularMatrix& operator/=(T number) { for(std::size_t i = 0; i != cols; ++i) _data[i] /= number; @@ -316,14 +304,11 @@ template class RectangularMatrix { /** * @brief Divide matrix with number * - * @see operator/=(), operator/(U, const RectangularMatrix&) + * @see operator/=(T), + * operator/(T, const RectangularMatrix&) */ - #ifndef DOXYGEN_GENERATING_OUTPUT - template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number) const { - #else - template RectangularMatrix operator/(U number) const { - #endif - return RectangularMatrix(*this)/=number; + RectangularMatrix operator/(T number) const { + return RectangularMatrix(*this) /= number; } /** @@ -385,13 +370,16 @@ template 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 inline RectangularMatrix operator*(U number, const RectangularMatrix& matrix) { -#else -template inline typename std::enable_if::value, RectangularMatrix>::type operator*(U number, const RectangularMatrix& matrix) { -#endif +template inline RectangularMatrix operator*( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const RectangularMatrix& matrix) +{ return matrix*number; } @@ -401,13 +389,16 @@ template 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 inline RectangularMatrix operator/(U number, const RectangularMatrix& matrix) { -#else -template inline typename std::enable_if::value, RectangularMatrix>::type operator/(U number, const RectangularMatrix& matrix) { -#endif +template inline RectangularMatrix operator/( + #ifdef DOXYGEN_GENERATING_OUTPUT + T + #else + typename std::common_type::type + #endif + number, const RectangularMatrix& matrix) +{ RectangularMatrix out; for(std::size_t i = 0; i != cols; ++i) @@ -502,20 +493,42 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit __VA_ARGS__ operator-(const Math::RectangularMatrix& other) const { \ return Math::RectangularMatrix::operator-(other); \ } \ - template typename std::enable_if::value, __VA_ARGS__&>::type operator*=(U number) { \ + __VA_ARGS__& operator*=(T number) { \ Math::RectangularMatrix::operator*=(number); \ return *this; \ } \ - template typename std::enable_if::value, __VA_ARGS__>::type operator*(U number) const { \ + __VA_ARGS__ operator*(T number) const { \ return Math::RectangularMatrix::operator*(number); \ } \ - template typename std::enable_if::value, __VA_ARGS__&>::type operator/=(U number) { \ + __VA_ARGS__& operator/=(T number) { \ Math::RectangularMatrix::operator/=(number); \ return *this; \ } \ - template typename std::enable_if::value, __VA_ARGS__>::type operator/(U number) const { \ + __VA_ARGS__ operator/(T number) const { \ return Math::RectangularMatrix::operator/(number); \ } + +#define MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(...) \ + template inline __VA_ARGS__ operator*(typename std::common_type::type number, const __VA_ARGS__& matrix) { \ + return number*static_cast&>(matrix); \ + } \ + template inline __VA_ARGS__ operator/(typename std::common_type::type number, const __VA_ARGS__& matrix) { \ + return number/static_cast&>(matrix); \ + } \ + template inline __VA_ARGS__ operator*(const Vector& vector, const RectangularMatrix& matrix) { \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + } + +#define MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(size, Type) \ + template inline Type operator*(typename std::common_type::type number, const Type& matrix) { \ + return number*static_cast&>(matrix); \ + } \ + template inline Type operator/(typename std::common_type::type number, const Type& matrix) { \ + return number/static_cast&>(matrix); \ + } \ + template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + } #endif template inline RectangularMatrix RectangularMatrix::fromDiagonal(const Vector& diagonal) { diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 598dfde17..4aa2a541e 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -80,6 +80,9 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void vector(); + void subclassTypes(); + void subclass(); + void debug(); void configuration(); }; @@ -117,6 +120,9 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::vector, + &RectangularMatrixTest::subclassTypes, + &RectangularMatrixTest::subclass, + &RectangularMatrixTest::debug, &RectangularMatrixTest::configuration}); } @@ -308,19 +314,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() { @@ -394,6 +393,110 @@ void RectangularMatrixTest::vector() { CORRADE_COMPARE(Matrix4x3i::fromVector(b), a); } +template class BasicMat: public Math::RectangularMatrix { + public: + template BasicMat(U&&... args): Math::RectangularMatrix{std::forward(args)...} {} + + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(size, size, BasicMat) +}; + +MAGNUM_MATRIX_OPERATOR_IMPLEMENTATION(BasicMat) + +template class BasicMat2x2: public BasicMat<2, T> { + public: + template BasicMat2x2(U&&... args): BasicMat<2, T>{std::forward(args)...} {} + + MAGNUM_RECTANGULARMATRIX_SUBCLASS_IMPLEMENTATION(2, 2, BasicMat2x2) +}; + +MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(2, BasicMat2x2) + +typedef BasicMat2x2 Mat2x2; + +void RectangularMatrixTest::subclassTypes() { + Float* const data = nullptr; + const Float* const cdata = nullptr; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Const operators */ + const Mat2x2 c; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same()), Mat2x2>::value)); + + /* Assignment operators */ + Mat2x2 a; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + /* Operators on variable-sized matrix */ + const BasicMat<3, Float> c2; + CORRADE_VERIFY((std::is_same>::value)); + CORRADE_VERIFY((std::is_same>::value)); + CORRADE_VERIFY((std::is_same()), 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), From 88168e259befb396c5cbe8f85cd7e65b87cebf0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:22:31 +0200 Subject: [PATCH 10/18] Math: test also Matrix subclass function implementations. Similarly to what is already done for Vector and RectangularMatrix. --- src/Math/Test/MatrixTest.cpp | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index 9ba7c95b5..a8c160de3 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/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}); } @@ -280,6 +287,62 @@ void MatrixTest::invertedOrthogonal() { CORRADE_COMPARE(a.invertedOrthogonal(), a.inverted()); } +template class BasicVec2: public Math::Vector<2, T> { + public: + template BasicVec2(U&&... args): Math::Vector<2, T>{std::forward(args)...} {} +}; + +template class BasicMat2: public Math::Matrix<2, T> { + public: + template BasicMat2(U&&... args): Math::Matrix<2, T>{std::forward(args)...} {} + + MAGNUM_MATRIX_SUBCLASS_IMPLEMENTATION(2, BasicMat2, BasicVec2) +}; + +typedef BasicVec2 Vec2; +typedef BasicMat2 Mat2; + +void MatrixTest::subclassTypes() { + const Mat2 c; + Mat2 a; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + const Mat2 c2; + const Vec2 cv; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::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), From e2c8e8c86708be0e715e9e95b3b57528f41a2163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:23:31 +0200 Subject: [PATCH 11/18] Math: no need to explicitly overload operator=(). It is created automatically. --- src/Math/RectangularMatrix.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index 0b445cd60..b1d700b00 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -471,11 +471,6 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return *reinterpret_cast(data); \ } \ \ - __VA_ARGS__& operator=(const Math::RectangularMatrix& other) { \ - Math::RectangularMatrix::operator=(other); \ - return *this; \ - } \ - \ __VA_ARGS__ operator-() const { \ return Math::RectangularMatrix::operator-(); \ } \ From 50ec325c78c40884f7933eb1db4544e08762f4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 17:24:05 +0200 Subject: [PATCH 12/18] Math: fix and test RectangularMatrix*Vector operation. How did I forget to test that? --- src/Math/RectangularMatrix.h | 4 ++-- src/Math/Test/RectangularMatrixTest.cpp | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index b1d700b00..c867564ed 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -328,8 +328,8 @@ template class RectangularMatrix { * (\boldsymbol {Aa})_i = \sum_{k=0}^{m-1} \boldsymbol A_{ki} \boldsymbol a_k * @f] */ - Vector operator*(const Vector& other) const { - return operator*(RectangularMatrix<1, rows, T>(other))[0]; + Vector operator*(const Vector& other) const { + return operator*(RectangularMatrix<1, cols, T>(other))[0]; } /** diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index 4aa2a541e..b1104fa1b 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -74,6 +74,7 @@ class RectangularMatrixTest: public Corrade::TestSuite::Tester { void addSubtract(); void multiplyDivide(); void multiply(); + void multiplyVector(); void transposed(); void diagonal(); @@ -94,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() { @@ -114,6 +120,7 @@ RectangularMatrixTest::RectangularMatrixTest() { &RectangularMatrixTest::addSubtract, &RectangularMatrixTest::multiplyDivide, &RectangularMatrixTest::multiply, + &RectangularMatrixTest::multiplyVector, &RectangularMatrixTest::transposed, &RectangularMatrixTest::diagonal, @@ -349,6 +356,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), From 8f513b1001ddabd3af943aac985b5efab11f0699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 22:32:53 +0200 Subject: [PATCH 13/18] Math: added bitwise operations for integer Vector. --- src/Math/Test/VectorTest.cpp | 41 +++++- src/Math/Vector.h | 242 +++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+), 1 deletion(-) diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index b6484e5e6..b12a6a4da 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -74,6 +74,7 @@ class VectorTest: public Corrade::TestSuite::Tester { void multiplyDivideIntegral(); void multiplyDivideComponentWise(); void multiplyDivideComponentWiseIntegral(); + void bitwise(); void compare(); void compareComponentWise(); @@ -127,6 +128,7 @@ VectorTest::VectorTest() { &VectorTest::multiplyDivideIntegral, &VectorTest::multiplyDivideComponentWise, &VectorTest::multiplyDivideComponentWiseIntegral, + &VectorTest::bitwise, &VectorTest::compare, &VectorTest::compareComponentWise, @@ -335,6 +337,21 @@ void VectorTest::multiplyDivideComponentWiseIntegral() { /* 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); } @@ -462,9 +479,22 @@ void VectorTest::subclassTypes() { CORRADE_VERIFY((std::is_same::value)); CORRADE_VERIFY((std::is_same::value)); - /* Integer multiplication/division */ + /* Bitwise operations */ const Vec2i ci; Vec2i i; + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same> 1), Vec2i>::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same::value)); + CORRADE_VERIFY((std::is_same>= 1), Vec2i&>::value)); + + /* Integer multiplication/division */ CORRADE_VERIFY((std::is_same::value)); CORRADE_VERIFY((std::is_same::value)); CORRADE_VERIFY((std::is_same::value)); @@ -498,6 +528,15 @@ void VectorTest::subclass() { 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)); diff --git a/src/Math/Vector.h b/src/Math/Vector.h index 28dc4daf8..dc5980e0f 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -563,6 +563,210 @@ template inline Vector operator/( return out; } +/** @relates Vector +@brief Bitwise NOT of integral vector +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator~(const Vector& vector) { + Vector out; + + for(std::size_t i = 0; i != size; ++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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value, Vector&>::type +#endif +operator&=(Vector& a, const Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator&(const Vector& a, const Vector& b) { + Vector copy(a); + return copy &= b; +} + +/** @relates Vector +@brief Do bitwise OR of two integral vectors and assign + +The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value, Vector&>::type +#endif +operator|=(Vector& a, const Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator|(const Vector& a, const Vector& b) { + Vector copy(a); + return copy |= b; +} + +/** @relates Vector +@brief Do bitwise XOR of two integral vectors and assign + +The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value, Vector&>::type +#endif +operator^=(Vector& a, const Vector& 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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator^(const Vector& a, const Vector& b) { + Vector copy(a); + return copy ^= b; +} + +/** @relates Vector +@brief Do bitwise left shift of integral vector and assign + +The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value, Vector&>::type +#endif +operator<<=(Vector& vector, + #ifdef DOXYGEN_GENERATING_OUTPUT + Integral + #else + typename std::common_type::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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator<<(const Vector& vector, + #ifdef DOXYGEN_GENERATING_OUTPUT + Integral + #else + typename std::common_type::type + #endif + shift) +{ + Vector copy(vector); + return copy <<= shift; +} + +/** @relates Vector +@brief Do bitwise right shift of integral vector and assign + +The computation is done in-place. +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector& +#else +typename std::enable_if::value, Vector&>::type +#endif +operator>>=(Vector& vector, + #ifdef DOXYGEN_GENERATING_OUTPUT + Integral + #else + typename std::common_type::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 inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Vector +#else +typename std::enable_if::value, Vector>::type +#endif +operator>>(const Vector& vector, + #ifdef DOXYGEN_GENERATING_OUTPUT + Integral + #else + typename std::common_type::type + #endif + shift) { + Vector copy(vector); + return copy >>= shift; +} + /** @relates Vector @brief Multiply integral vector with floating-point number and assign @@ -853,6 +1057,44 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return number/static_cast&>(vector); \ } \ \ + template inline typename std::enable_if::value, Type>::type operator~(const Type& vector) { \ + return ~static_cast&>(vector); \ + } \ + template inline typename std::enable_if::value, Type&>::type operator&=(Type& a, const Math::Vector& b) { \ + static_cast&>(a) &= b; \ + return a; \ + } \ + template inline typename std::enable_if::value, Type>::type operator&(const Type& a, const Math::Vector& b) { \ + return static_cast&>(a) & b; \ + } \ + template inline typename std::enable_if::value, Type&>::type operator|=(Type& a, const Math::Vector& b) { \ + static_cast&>(a) |= b; \ + return a; \ + } \ + template inline typename std::enable_if::value, Type>::type operator|(const Type& a, const Math::Vector& b) { \ + return static_cast&>(a) | b; \ + } \ + template inline typename std::enable_if::value, Type&>::type operator^=(Type& a, const Math::Vector& b) { \ + static_cast&>(a) ^= b; \ + return a; \ + } \ + template inline typename std::enable_if::value, Type>::type operator^(const Type& a, const Math::Vector& b) { \ + return static_cast&>(a) ^ b; \ + } \ + template inline typename std::enable_if::value, Type&>::type operator<<=(Type& vector, typename std::common_type::type shift) { \ + static_cast&>(vector) <<= shift; \ + return vector; \ + } \ + template inline typename std::enable_if::value, Type>::type operator<<(const Type& vector, typename std::common_type::type shift) { \ + return static_cast&>(vector) << shift; \ + } \ + template inline typename std::enable_if::value, Type&>::type operator>>=(Type& vector, typename std::common_type::type shift) { \ + static_cast&>(vector) >>= shift; \ + return vector; \ + } \ + template inline typename std::enable_if::value, Type>::type operator>>(const Type& vector, typename std::common_type::type shift) { \ + return static_cast&>(vector) >> shift; \ + } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& vector, FloatingPoint number) { \ static_cast&>(vector) *= number; \ return vector; \ From caa98895955dfc8db14dd6fc748f6eb44d9e086f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 22:33:34 +0200 Subject: [PATCH 14/18] Use `size >> mipLevel` to compute image size at given mip level. This is so awesome trick. --- src/AbstractTexture.cpp | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index 1f2f7b345..481679606 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -683,10 +683,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); } } @@ -720,15 +718,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) { for(GLenum face: {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -736,17 +731,14 @@ void AbstractTexture::storageImplementationFallback(const GLenum target, const G GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}) - (this->*image2DImplementation)(face, level, internalFormat, levelSize, format, type, nullptr); - levelSize = Math::max(Vector2i(1), levelSize/2); + (this->*image2DImplementation)(face, 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 @@ -785,10 +777,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 @@ -800,10 +790,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 From 2893d12ece8779d2bf010eab919c92a2b82b2378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 22:44:18 +0200 Subject: [PATCH 15/18] Updated matrix/vector documentation. --- doc/matrix-vector.dox | 180 +++++++++++++++++++++++++++++------------- 1 file changed, 126 insertions(+), 54 deletions(-) diff --git a/doc/matrix-vector.dox b/doc/matrix-vector.dox index 82ab2d98b..c5703196a 100644 --- a/doc/matrix-vector.dox +++ b/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`. 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 black1; // {0.0f, 0.0f, 0.0f, 1.0f} -Color4 black2; // {0, 0, 0, 255} +Color4 black1; // {0.0f, 0.0f, 0.0f, 1.0f} +BasicColor4 black2; // {0, 0, 0, 255} @endcode Most common and most efficient way to create vector is to pass all values to constructor, matrix is created by passing all column vectors to the constructor. @code -Vector3 vec(0, 1, 2); +Vector3i vec(0, 1, 2); -Matrix3 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 diag(Matrix3::Identity, 2); // diagonal set to 2, zeros elsewhere -Vector3 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 b, c; -Matrix3 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 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 floating(1.3f, 2.7f, -15.0f, 7.0f); -Vector4 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 a; +Vector4i a; Int x = a.x(); a.y() += 5; -Vector3 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 color(80, 116, 34); +BasicColor3 lighter = color*1.5f; // lighter = {120, 174, 51} + +Vector3i a(4, 18, -90); +Vector3 multiplier(2.2f, 0.25f, 0.1f); +Vector3i b = a*multiplier; // b == {8, 4, -9} +Vector3 c = Vector3(a)*multiplier; // c == {8.0f, 4.5f, -9.0f} +@endcode + +You can use also all bitwise operations on integral vectors: +@code +Vector2i size(256, 256); +Vector2i mipLevel3Size = size >> 3; // == {32, 32} +@endcode + +Matrices can be added, subtracted and multiplied with matrix multiplication. +@code +Matrix3x2 a; +Matrix3x2 b; +Matrix3x2 c = a + (-b); + +Matrix2x3 d; +Matrix2x2 e = d*b; +Matrix3x3 f = b*d; +@endcode + +You can also multiply (properly sized) vectors with matrices. These operations +are just convenience shortcuts for multiplying with single-column matrices: +@code +Matrix3x4 a; +Vector3 b; +Vector4 c = a*b; + +Math::RectangularMatrix<4, 1, Float> d; +Matrix4x3 e = b*d; @endcode @section matrix-vector-column-major Matrices are column-major and vectors are columns @@ -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 mat({0, 1, 2}, - {3, 4, 5}, - {6, 7, 8}); // first column is {0, 1, 2} +Math::Matrix3 mat({0, 1, 2}, + {3, 4, 5}, + {6, 7, 8}); // first column is {0, 1, 2} @endcode - Element accessing order is also column-major, thus the bracket operator is accessing columns. Returned vector has also its own bracket operator, which is then indexing rows. @code mat[0] *= 2; // first column -mat[2][0] = 5; // first element of 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 From 7d873302497c1de3e792f22b07e0a8d7c62e59f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 2 Sep 2013 23:38:02 +0200 Subject: [PATCH 16/18] Gaah. --- src/Math/RectangularMatrix.h | 4 ++-- src/Math/Vector.h | 42 ++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Math/RectangularMatrix.h b/src/Math/RectangularMatrix.h index c867564ed..901dbb0cd 100644 --- a/src/Math/RectangularMatrix.h +++ b/src/Math/RectangularMatrix.h @@ -511,7 +511,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return number/static_cast&>(matrix); \ } \ template inline __VA_ARGS__ operator*(const Vector& vector, const RectangularMatrix& matrix) { \ - return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ } #define MAGNUM_MATRIXn_OPERATOR_IMPLEMENTATION(size, Type) \ @@ -522,7 +522,7 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit return number/static_cast&>(matrix); \ } \ template inline Type operator*(const Vector& vector, const RectangularMatrix& matrix) { \ - return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ + return Math::RectangularMatrix<1, size, T>(vector)*matrix; \ } #endif diff --git a/src/Math/Vector.h b/src/Math/Vector.h index dc5980e0f..e32c41f2d 100644 --- a/src/Math/Vector.h +++ b/src/Math/Vector.h @@ -1051,84 +1051,84 @@ extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utilit #define MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(size, Type) \ template inline Type operator*(typename std::common_type::type number, const Type& vector) { \ - return number*static_cast&>(vector); \ + return number*static_cast&>(vector); \ } \ template inline Type operator/(typename std::common_type::type number, const Type& vector) { \ - return number/static_cast&>(vector); \ + return number/static_cast&>(vector); \ } \ \ template inline typename std::enable_if::value, Type>::type operator~(const Type& vector) { \ - return ~static_cast&>(vector); \ + return ~static_cast&>(vector); \ } \ template inline typename std::enable_if::value, Type&>::type operator&=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) &= b; \ + static_cast&>(a) &= b; \ return a; \ } \ template inline typename std::enable_if::value, Type>::type operator&(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) & b; \ + return static_cast&>(a) & b; \ } \ template inline typename std::enable_if::value, Type&>::type operator|=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) |= b; \ + static_cast&>(a) |= b; \ return a; \ } \ template inline typename std::enable_if::value, Type>::type operator|(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) | b; \ + return static_cast&>(a) | b; \ } \ template inline typename std::enable_if::value, Type&>::type operator^=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) ^= b; \ + static_cast&>(a) ^= b; \ return a; \ } \ template inline typename std::enable_if::value, Type>::type operator^(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a) ^ b; \ + return static_cast&>(a) ^ b; \ } \ template inline typename std::enable_if::value, Type&>::type operator<<=(Type& vector, typename std::common_type::type shift) { \ - static_cast&>(vector) <<= shift; \ + static_cast&>(vector) <<= shift; \ return vector; \ } \ template inline typename std::enable_if::value, Type>::type operator<<(const Type& vector, typename std::common_type::type shift) { \ return static_cast&>(vector) << shift; \ } \ template inline typename std::enable_if::value, Type&>::type operator>>=(Type& vector, typename std::common_type::type shift) { \ - static_cast&>(vector) >>= shift; \ + static_cast&>(vector) >>= shift; \ return vector; \ } \ template inline typename std::enable_if::value, Type>::type operator>>(const Type& vector, typename std::common_type::type shift) { \ return static_cast&>(vector) >> shift; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& vector, FloatingPoint number) { \ - static_cast&>(vector) *= number; \ + static_cast&>(vector) *= number; \ return vector; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& vector, FloatingPoint number) { \ - return static_cast&>(vector)*number; \ + return static_cast&>(vector)*number; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(FloatingPoint number, const Type& vector) { \ - return number*static_cast&>(vector); \ + return number*static_cast&>(vector); \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& vector, FloatingPoint number) { \ - static_cast&>(vector) /= number; \ + static_cast&>(vector) /= number; \ return vector; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& vector, FloatingPoint number) { \ - return static_cast&>(vector)/number; \ + return static_cast&>(vector)/number; \ } \ \ template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator*=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) *= b; \ + static_cast&>(a) *= b; \ return a; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a)*b; \ + return static_cast&>(a)*b; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator*(const Math::Vector& a, const Type& b) { \ - return a*static_cast&>(b); \ + return a*static_cast&>(b); \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type&>::type operator/=(Type& a, const Math::Vector& b) { \ - static_cast&>(a) /= b; \ + static_cast&>(a) /= b; \ return a; \ } \ template inline typename std::enable_if::value && std::is_floating_point::value, Type>::type operator/(const Type& a, const Math::Vector& b) { \ - return static_cast&>(a)/b; \ + return static_cast&>(a)/b; \ } #endif From 8935d8c721135a8fb8336d86b4650e5bbe53c9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 4 Sep 2013 12:35:32 +0200 Subject: [PATCH 17/18] Shapes: preparation for non-boolean collision queries. --- Doxyfile | 2 +- doc/coding-style.dox | 6 +++--- src/Shapes/AxisAlignedBox.h | 4 ++-- src/Shapes/Capsule.h | 8 ++++---- src/Shapes/Cylinder.h | 8 ++++---- src/Shapes/Plane.h | 8 ++++---- src/Shapes/Sphere.h | 14 +++++++------- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Doxyfile b/Doxyfile index 9bb7567bd..18a8b85e8 100644 --- a/Doxyfile +++ b/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}=gl\1()" \ "fn_gl_extension{3}=gl\1\2()" \ diff --git a/doc/coding-style.dox b/doc/coding-style.dox index 8c686005d..d520b14cf 100644 --- a/doc/coding-style.dox +++ b/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 diff --git a/src/Shapes/AxisAlignedBox.h b/src/Shapes/AxisAlignedBox.h index 750689828..50aa7210f 100644 --- a/src/Shapes/AxisAlignedBox.h +++ b/src/Shapes/AxisAlignedBox.h @@ -81,7 +81,7 @@ template class MAGNUM_SHAPES_EXPORT AxisAlignedBox { _max = max; } - /** @brief Collision with point */ + /** @brief %Collision occurence with point */ bool operator%(const Point& 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 inline bool operator%(const Point& a, const AxisAlignedBox& b) { return b % a; } }} diff --git a/src/Shapes/Capsule.h b/src/Shapes/Capsule.h index c0f0d4bbc..d73f506d1 100644 --- a/src/Shapes/Capsule.h +++ b/src/Shapes/Capsule.h @@ -89,10 +89,10 @@ template 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& other) const; - /** @brief Collision with sphere */ + /** @brief %Collision occurence with sphere */ bool operator%(const Sphere& 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 inline bool operator%(const Point& a, const Capsule& b) { return b % a; } -/** @collisionoperator{Sphere,Capsule} */ +/** @collisionoccurenceoperator{Sphere,Capsule} */ template inline bool operator%(const Sphere& a, const Capsule& b) { return b % a; } }} diff --git a/src/Shapes/Cylinder.h b/src/Shapes/Cylinder.h index e9a04d33b..22ff553a1 100644 --- a/src/Shapes/Cylinder.h +++ b/src/Shapes/Cylinder.h @@ -89,10 +89,10 @@ template 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& other) const; - /** @brief Collision with sphere */ + /** @brief %Collision occurence with sphere */ bool operator%(const Sphere& 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 inline bool operator%(const Point& a, const Cylinder& b) { return b % a; } -/** @collisionoperator{Sphere,Cylinder} */ +/** @collisionoccurenceoperator{Sphere,Cylinder} */ template inline bool operator%(const Sphere& a, const Cylinder& b) { return b % a; } }} diff --git a/src/Shapes/Plane.h b/src/Shapes/Plane.h index 81f1608e5..c3a4d6a7c 100644 --- a/src/Shapes/Plane.h +++ b/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; } diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index 17d27bdd0..e402f9c9e 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -79,16 +79,16 @@ template 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& other) const; - /** @brief Collision with line */ + /** @brief %Collision occurence with line */ bool operator%(const Line& other) const; - /** @brief Collision with line segment */ + /** @brief %Collision occurence with line segment */ bool operator%(const LineSegment& other) const; - /** @brief Collision with sphere */ + /** @brief %Collision occurence with sphere */ bool operator%(const Sphere& 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 inline bool operator%(const Point& a, const Sphere& b) { return b % a; } -/** @collisionoperator{Line,Sphere} */ +/** @collisionoccurenceoperator{Line,Sphere} */ template inline bool operator%(const Line& a, const Sphere& b) { return b % a; } -/** @collisionoperator{LineSegment,Sphere} */ +/** @collisionoccurenceoperator{LineSegment,Sphere} */ template inline bool operator%(const LineSegment& a, const Sphere& b) { return b % a; } }} From 5bad9685d1f45d6b183550a4c41528051a8b1910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 4 Sep 2013 12:45:50 +0200 Subject: [PATCH 18/18] Doc: added Khronos OpenGL ES presentation to Best Practices. --- doc/best-practices.dox | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/best-practices.dox b/doc/best-practices.dox index 2cddea322..1d64c1929 100644 --- a/doc/best-practices.dox +++ b/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