From ca3b0f7d63c293e70dca65ecc8907e9bb8fa2abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 12:20:07 +0100 Subject: [PATCH 01/11] Added debug output operator for Buffer::Target. --- src/Buffer.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/Buffer.h | 3 +++ 2 files changed, 39 insertions(+) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index dd108bd2e..2fa92c0b2 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -221,4 +221,40 @@ bool Buffer::unmapImplementationDSA() { } #endif +#ifndef DOXYGEN_GENERATING_OUTPUT +Debug operator<<(Debug debug, Buffer::Target value) { + switch(value) { + #define _c(value) case Buffer::Target::value: return debug << "Buffer::Target::" #value; + _c(Array) + #ifndef MAGNUM_TARGET_GLES + _c(AtomicCounter) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(CopyRead) + _c(CopyWrite) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(DispatchIndirect) + _c(DrawIndirect) + #endif + _c(ElementArray) + #ifndef MAGNUM_TARGET_GLES2 + _c(PixelPack) + _c(PixelUnpack) + #endif + #ifndef MAGNUM_TARGET_GLES + _c(ShaderStorage) + _c(Texture) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(TransformFeedback) + _c(Uniform) + #endif + #undef _c + } + + return debug << "Buffer::Target::(invalid)"; +} +#endif + } diff --git a/src/Buffer.h b/src/Buffer.h index 6f28cfb23..9d3e0c7e9 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -781,6 +781,9 @@ class MAGNUM_EXPORT Buffer { CORRADE_ENUMSET_OPERATORS(Buffer::MapFlags) +/** @debugoperator{Magnum::Buffer} */ +Debug MAGNUM_EXPORT operator<<(Debug debug, Buffer::Target value); + } #endif From 45ba444fb8943682a5e59b490a0e0e00694271fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 17:41:44 +0100 Subject: [PATCH 02/11] Math: properly test conversion constexpr also in Vector subclasses. --- src/Math/Test/Vector2Test.cpp | 17 ++++++++++++----- src/Math/Test/Vector3Test.cpp | 19 +++++++++++++------ src/Math/Test/Vector4Test.cpp | 21 ++++++++++++++------- src/Math/Test/VectorTest.cpp | 10 ++++------ 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index 1a4183445..b6a8772e4 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -126,11 +126,18 @@ void Vector2Test::constructCopy() { } void Vector2Test::convert() { - Vec2 a{1.5f, 2.0f}; - Vector2 b(1.5f, 2.0f); - CORRADE_COMPARE(Vector2(a), b); - CORRADE_COMPARE(Vec2(b).x, a.x); - CORRADE_COMPARE(Vec2(b).y, a.y); + constexpr Vec2 a{1.5f, 2.0f}; + constexpr Vector2 b(1.5f, 2.0f); + + constexpr Vector2 c(a); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Vec2 d(b); + CORRADE_COMPARE(d.x, a.x); + CORRADE_COMPARE(d.y, a.y); } void Vector2Test::access() { diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index 05d5a697d..8e3d6b1b9 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -139,12 +139,19 @@ void Vector3Test::constructCopy() { } void Vector3Test::convert() { - Vec3 a{1.5f, 2.0f, -3.5f}; - Vector3 b(1.5f, 2.0f, -3.5f); - CORRADE_COMPARE(Vector3(a), b); - CORRADE_COMPARE(Vec3(b).x, a.x); - CORRADE_COMPARE(Vec3(b).y, a.y); - CORRADE_COMPARE(Vec3(b).z, a.z); + constexpr Vec3 a{1.5f, 2.0f, -3.5f}; + constexpr Vector3 b(1.5f, 2.0f, -3.5f); + + constexpr Vector3 c(a); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Vec3 d(b); + CORRADE_COMPARE(d.x, a.x); + CORRADE_COMPARE(d.y, a.y); + CORRADE_COMPARE(d.z, a.z); } void Vector3Test::access() { diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index 8e09b296c..581b5c597 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -136,13 +136,20 @@ void Vector4Test::constructCopy() { } void Vector4Test::convert() { - Vec4 a{1.5f, 2.0f, -3.5f, -0.5f}; - Vector4 b(1.5f, 2.0f, -3.5f, -0.5f); - CORRADE_COMPARE(Vector4(a), b); - CORRADE_COMPARE(Vec4(b).x, a.x); - CORRADE_COMPARE(Vec4(b).y, a.y); - CORRADE_COMPARE(Vec4(b).z, a.z); - CORRADE_COMPARE(Vec4(b).w, a.w); + constexpr Vec4 a{1.5f, 2.0f, -3.5f, -0.5f}; + constexpr Vector4 b(1.5f, 2.0f, -3.5f, -0.5f); + + constexpr Vector4 c(a); + CORRADE_COMPARE(c, b); + + #ifndef CORRADE_GCC46_COMPATIBILITY + constexpr /* Not constexpr under GCC < 4.7 */ + #endif + Vec4 d(b); + CORRADE_COMPARE(d.x, a.x); + CORRADE_COMPARE(d.y, a.y); + CORRADE_COMPARE(d.z, a.z); + CORRADE_COMPARE(d.w, a.w); } void Vector4Test::access() { diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index b8069ffb2..dd5d1c553 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -202,17 +202,15 @@ void VectorTest::convert() { constexpr Vector3 b(1.5f, 2.0f, -3.5f); #ifndef CORRADE_GCC46_COMPATIBILITY - constexpr Vector3 c(a); - #else - Vector3 c(a); /* Not constexpr under GCC < 4.7 */ + constexpr /* Not constexpr under GCC < 4.7 */ #endif + Vector3 c(b); CORRADE_COMPARE(c, b); #ifndef CORRADE_GCC46_COMPATIBILITY - constexpr Vec3 d(b); - #else - Vec3 d(b); /* Not constexpr under GCC < 4.7 */ + constexpr /* Not constexpr under GCC < 4.7 */ #endif + Vec3 d(b); CORRADE_COMPARE(d.x, a.x); CORRADE_COMPARE(d.y, a.y); CORRADE_COMPARE(d.z, a.z); From cc938a29dd204408c7947ed2251254044bf65ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 17:44:52 +0100 Subject: [PATCH 03/11] Math: test that implicit conversion of T to Vector won't compile. "Won't compile" tests are another awesome feature of C++11. --- src/Math/Test/Vector2Test.cpp | 3 +++ src/Math/Test/Vector3Test.cpp | 3 +++ src/Math/Test/Vector4Test.cpp | 3 +++ src/Math/Test/VectorTest.cpp | 3 +++ 4 files changed, 12 insertions(+) diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index b6a8772e4..622c303d4 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -107,6 +107,9 @@ void Vector2Test::constructOneValue() { Vector2 a(3.0f); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(a, Vector2(3.0f, 3.0f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector2Test::constructConversion() { diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index 8e3d6b1b9..1dc913f47 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -114,6 +114,9 @@ void Vector3Test::constructOneValue() { Vector3 a(-3.0f); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(a, Vector3(-3.0f, -3.0f, -3.0f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector3Test::constructParts() { diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index 581b5c597..3a18d019a 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -111,6 +111,9 @@ void Vector4Test::constructOneValue() { Vector4 a(4.3f); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(a, Vector4(4.3f, 4.3f, 4.3f, 4.3f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector4Test::constructParts() { diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index dd5d1c553..47d194992 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -165,6 +165,9 @@ void VectorTest::constructOneValue() { #endif CORRADE_COMPARE(a, Vector4(7.25f, 7.25f, 7.25f, 7.25f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void VectorTest::constructOneComponent() { From 1d5e3fee7afaabbe6450390bc6cc88d851acc9aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 17:46:35 +0100 Subject: [PATCH 04/11] Math: test that implicit conversion of underlying type can't compile. --- src/Math/Test/Matrix3Test.cpp | 3 +++ src/Math/Test/Matrix4Test.cpp | 3 +++ src/Math/Test/MatrixTest.cpp | 3 +++ src/Math/Test/RectangularMatrixTest.cpp | 3 +++ src/Math/Test/Vector2Test.cpp | 3 +++ src/Math/Test/Vector3Test.cpp | 3 +++ src/Math/Test/Vector4Test.cpp | 3 +++ src/Math/Test/VectorTest.cpp | 3 +++ 8 files changed, 24 insertions(+) diff --git a/src/Math/Test/Matrix3Test.cpp b/src/Math/Test/Matrix3Test.cpp index eeaa8dd8b..5ff187c9a 100644 --- a/src/Math/Test/Matrix3Test.cpp +++ b/src/Math/Test/Matrix3Test.cpp @@ -135,6 +135,9 @@ void Matrix3Test::constructConversion() { CORRADE_COMPARE(b, Matrix3i({3, 5, 8}, {4, 4, 7}, {7, -1, 8})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Matrix3Test::constructCopy() { diff --git a/src/Math/Test/Matrix4Test.cpp b/src/Math/Test/Matrix4Test.cpp index 771b5dba7..a00d5c781 100644 --- a/src/Math/Test/Matrix4Test.cpp +++ b/src/Math/Test/Matrix4Test.cpp @@ -154,6 +154,9 @@ void Matrix4Test::constructConversion() { {4, 4, 7, 2}, {1, 2, 3, -1}, {7, -1, 8, -1})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Matrix4Test::constructCopy() { diff --git a/src/Math/Test/MatrixTest.cpp b/src/Math/Test/MatrixTest.cpp index 62973756f..92061d41d 100644 --- a/src/Math/Test/MatrixTest.cpp +++ b/src/Math/Test/MatrixTest.cpp @@ -132,6 +132,9 @@ void MatrixTest::constructConversion() { Vector4i(4, 4, 7, 2), Vector4i(1, 2, 3, -1), Vector4i(7, -1, 8, -1))); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void MatrixTest::constructCopy() { diff --git a/src/Math/Test/RectangularMatrixTest.cpp b/src/Math/Test/RectangularMatrixTest.cpp index d311231c3..9ce624889 100644 --- a/src/Math/Test/RectangularMatrixTest.cpp +++ b/src/Math/Test/RectangularMatrixTest.cpp @@ -134,6 +134,9 @@ void RectangularMatrixTest::constructConversion() { CORRADE_COMPARE(b, Matrix2i(Vector2i( 1, 2), Vector2i(-15, 7))); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void RectangularMatrixTest::constructFromData() { diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index 622c303d4..37ba4ec9f 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -120,6 +120,9 @@ void Vector2Test::constructConversion() { Vector2i b(a); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(b, Vector2i(1, 2)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector2Test::constructCopy() { diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index 1dc913f47..baa1de9a2 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -133,6 +133,9 @@ void Vector3Test::constructConversion() { Vector3i b(a); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(b, Vector3i(1, 2, -3)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector3Test::constructCopy() { diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index 3a18d019a..a31d45e46 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -130,6 +130,9 @@ void Vector4Test::constructConversion() { Vector4i b(a); /* Not constexpr under GCC < 4.7 */ #endif CORRADE_COMPARE(b, Vector4i(1, -2, 3, 4)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector4Test::constructCopy() { diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index 47d194992..ece641e27 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -187,6 +187,9 @@ void VectorTest::constructConversion() { #endif CORRADE_COMPARE(b, Vector4i(1, 2, -15, 7)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void VectorTest::constructCopy() { From 213499e7bba4ca5e14434f3c2c62a43e60e0cb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 18:17:37 +0100 Subject: [PATCH 05/11] Math: test that implicit conversion from/to foreign types can't compile. --- src/Math/Test/Vector2Test.cpp | 4 ++++ src/Math/Test/Vector3Test.cpp | 4 ++++ src/Math/Test/Vector4Test.cpp | 4 ++++ src/Math/Test/VectorTest.cpp | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/Math/Test/Vector2Test.cpp b/src/Math/Test/Vector2Test.cpp index 37ba4ec9f..ec05fab05 100644 --- a/src/Math/Test/Vector2Test.cpp +++ b/src/Math/Test/Vector2Test.cpp @@ -144,6 +144,10 @@ void Vector2Test::convert() { Vec2 d(b); CORRADE_COMPARE(d.x, a.x); CORRADE_COMPARE(d.y, a.y); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector2Test::access() { diff --git a/src/Math/Test/Vector3Test.cpp b/src/Math/Test/Vector3Test.cpp index baa1de9a2..649cd1851 100644 --- a/src/Math/Test/Vector3Test.cpp +++ b/src/Math/Test/Vector3Test.cpp @@ -158,6 +158,10 @@ void Vector3Test::convert() { CORRADE_COMPARE(d.x, a.x); CORRADE_COMPARE(d.y, a.y); CORRADE_COMPARE(d.z, a.z); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector3Test::access() { diff --git a/src/Math/Test/Vector4Test.cpp b/src/Math/Test/Vector4Test.cpp index a31d45e46..447215890 100644 --- a/src/Math/Test/Vector4Test.cpp +++ b/src/Math/Test/Vector4Test.cpp @@ -156,6 +156,10 @@ void Vector4Test::convert() { CORRADE_COMPARE(d.y, a.y); CORRADE_COMPARE(d.z, a.z); CORRADE_COMPARE(d.w, a.w); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void Vector4Test::access() { diff --git a/src/Math/Test/VectorTest.cpp b/src/Math/Test/VectorTest.cpp index ece641e27..7c93976b6 100644 --- a/src/Math/Test/VectorTest.cpp +++ b/src/Math/Test/VectorTest.cpp @@ -220,6 +220,10 @@ void VectorTest::convert() { CORRADE_COMPARE(d.x, a.x); CORRADE_COMPARE(d.y, a.y); CORRADE_COMPARE(d.z, a.z); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void VectorTest::data() { From 51da8bd65b4f7634595c090b45e41540d91aa1fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 23:19:29 +0100 Subject: [PATCH 06/11] Math: updated Rectangle test to test constexpr functions. --- src/Math/Geometry/Test/RectangleTest.cpp | 72 ++++++++++++++++++------ 1 file changed, 56 insertions(+), 16 deletions(-) diff --git a/src/Math/Geometry/Test/RectangleTest.cpp b/src/Math/Geometry/Test/RectangleTest.cpp index 0120168ea..63fac06ac 100644 --- a/src/Math/Geometry/Test/RectangleTest.cpp +++ b/src/Math/Geometry/Test/RectangleTest.cpp @@ -33,9 +33,14 @@ class RectangleTest: public Corrade::TestSuite::Tester { public: RectangleTest(); + void construct(); + void constructDefault(); + void constructFromSize(); + void constructConversion(); + void constructCopy(); + void access(); void compare(); - void construct(); void size(); void debug(); @@ -46,17 +51,48 @@ typedef Geometry::Rectangle Rectanglei; typedef Vector2 Vector2i; RectangleTest::RectangleTest() { - addTests({&RectangleTest::access, + addTests({&RectangleTest::construct, + &RectangleTest::constructDefault, + &RectangleTest::constructFromSize, + &RectangleTest::constructConversion, + &RectangleTest::constructCopy, + + &RectangleTest::access, &RectangleTest::compare, - &RectangleTest::construct, &RectangleTest::size, &RectangleTest::debug}); } +void RectangleTest::construct() { + constexpr Rectanglei a({3, 5}, {23, 78}); + CORRADE_COMPARE(a, Rectanglei({3, 5}, {23, 78})); +} + +void RectangleTest::constructDefault() { + constexpr Rectanglei a; + CORRADE_COMPARE(a, Rectanglei({0, 0}, {0, 0})); +} + +void RectangleTest::constructFromSize() { + CORRADE_COMPARE(Rectanglei::fromSize({3, 5}, {23, 78}), Rectanglei({3, 5}, {26, 83})); +} + +void RectangleTest::constructConversion() { + constexpr Rectangle a({1.3f, 2.7f}, {-15.0f, 7.0f}); + constexpr Rectanglei b(a); + CORRADE_COMPARE(b, Rectanglei({1, 2}, {-15, 7})); +} + +void RectangleTest::constructCopy() { + constexpr Rectanglei a({3, 5}, {23, 78}); + constexpr Rectanglei b(a); + CORRADE_COMPARE(b, Rectanglei({3, 5}, {23, 78})); +} + void RectangleTest::access() { Rectanglei rect({34, 23}, {47, 30}); - const Rectanglei crect({34, 23}, {47, 30}); + constexpr Rectanglei crect({34, 23}, {47, 30}); CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23)); CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30)); @@ -64,12 +100,22 @@ void RectangleTest::access() { CORRADE_COMPARE(rect.top(), 30); CORRADE_COMPARE(rect.left(), 34); CORRADE_COMPARE(rect.right(), 47); - CORRADE_COMPARE(crect.bottomLeft(), Vector2i(34, 23)); - CORRADE_COMPARE(crect.topRight(), Vector2i(47, 30)); - CORRADE_COMPARE(crect.bottom(), 23); - CORRADE_COMPARE(crect.top(), 30); - CORRADE_COMPARE(crect.left(), 34); - CORRADE_COMPARE(crect.right(), 47); + CORRADE_COMPARE(rect.bottomLeft(), Vector2i(34, 23)); + CORRADE_COMPARE(rect.topRight(), Vector2i(47, 30)); + + constexpr Int bottom = crect.bottom(); + constexpr Int top = crect.top(); + constexpr Int left = crect.left(); + constexpr Int right = crect.right(); + CORRADE_COMPARE(bottom, 23); + CORRADE_COMPARE(top, 30); + CORRADE_COMPARE(left, 34); + CORRADE_COMPARE(right, 47); + + constexpr Vector2i bottomLeft = crect.bottomLeft(); + constexpr Vector2i topRight = crect.topRight(); + CORRADE_COMPARE(bottomLeft, Vector2i(34, 23)); + CORRADE_COMPARE(topRight, Vector2i(47, 30)); CORRADE_COMPARE(rect.topLeft(), Vector2i(34, 30)); CORRADE_COMPARE(rect.bottomRight(), Vector2i(47, 23)); @@ -81,12 +127,6 @@ void RectangleTest::compare() { CORRADE_VERIFY(Rectanglei({34, 23}, {47, 30}) != Rectanglei({35, 23}, {47, 30})); } -void RectangleTest::construct() { - CORRADE_COMPARE(Rectanglei(), Rectanglei({0, 0}, {0, 0})); - CORRADE_COMPARE(Rectanglei::fromSize({3, 5}, {23, 78}), Rectanglei({3, 5}, {26, 83})); - CORRADE_COMPARE(Rectanglei(Rectangle({1.3f, 2.7f}, {-15.0f, 7.0f})), Rectanglei({1, 2}, {-15, 7})); -} - void RectangleTest::size() { Rectanglei rect({34, 23}, {47, 30}); From 37c93468fd9c9851436cbc0f594d2da3899020fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 23:20:47 +0100 Subject: [PATCH 07/11] Math: test that implicit conversion of Rectangle type can't compile. --- src/Math/Geometry/Test/RectangleTest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Math/Geometry/Test/RectangleTest.cpp b/src/Math/Geometry/Test/RectangleTest.cpp index 63fac06ac..c53f35bc4 100644 --- a/src/Math/Geometry/Test/RectangleTest.cpp +++ b/src/Math/Geometry/Test/RectangleTest.cpp @@ -82,6 +82,9 @@ void RectangleTest::constructConversion() { constexpr Rectangle a({1.3f, 2.7f}, {-15.0f, 7.0f}); constexpr Rectanglei b(a); CORRADE_COMPARE(b, Rectanglei({1, 2}, {-15, 7})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void RectangleTest::constructCopy() { From 32d03530e11ed4a4f5beade57b9d46ec893add8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 23:26:14 +0100 Subject: [PATCH 08/11] Math: test that implicit conversion vector <-> complex/quat can't compile. --- src/Math/Test/ComplexTest.cpp | 4 ++++ src/Math/Test/DualComplexTest.cpp | 3 +++ src/Math/Test/DualQuaternionTest.cpp | 3 +++ src/Math/Test/QuaternionTest.cpp | 3 +++ 4 files changed, 13 insertions(+) diff --git a/src/Math/Test/ComplexTest.cpp b/src/Math/Test/ComplexTest.cpp index ecf939ada..1942d1a5d 100644 --- a/src/Math/Test/ComplexTest.cpp +++ b/src/Math/Test/ComplexTest.cpp @@ -126,6 +126,10 @@ void ComplexTest::constructFromVector() { constexpr Vector2 b(a); CORRADE_COMPARE(b, vec); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void ComplexTest::constructCopy() { diff --git a/src/Math/Test/DualComplexTest.cpp b/src/Math/Test/DualComplexTest.cpp index db1dce3c6..bd34f77b4 100644 --- a/src/Math/Test/DualComplexTest.cpp +++ b/src/Math/Test/DualComplexTest.cpp @@ -121,6 +121,9 @@ void DualComplexTest::constructDefault() { void DualComplexTest::constructFromVector() { constexpr DualComplex a(Vector2(1.5f, -3.0f)); CORRADE_COMPARE(a, DualComplex({1.0f, 0.0f}, {1.5f, -3.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void DualComplexTest::constructCopy() { diff --git a/src/Math/Test/DualQuaternionTest.cpp b/src/Math/Test/DualQuaternionTest.cpp index d484dceb5..93e364e94 100644 --- a/src/Math/Test/DualQuaternionTest.cpp +++ b/src/Math/Test/DualQuaternionTest.cpp @@ -119,6 +119,9 @@ void DualQuaternionTest::constructDefault() { void DualQuaternionTest::constructFromVector() { constexpr DualQuaternion a(Vector3(1.0f, 2.0f, 3.0f)); CORRADE_COMPARE(a, DualQuaternion({{0.0f, 0.0f, 0.0f}, 1.0f}, {{1.0f, 2.0f, 3.0f}, 0.0f})); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void DualQuaternionTest::constructCopy() { diff --git a/src/Math/Test/QuaternionTest.cpp b/src/Math/Test/QuaternionTest.cpp index 7cd6fc1d1..1ab42012f 100644 --- a/src/Math/Test/QuaternionTest.cpp +++ b/src/Math/Test/QuaternionTest.cpp @@ -128,6 +128,9 @@ void QuaternionTest::constructDefault() { void QuaternionTest::constructFromVector() { constexpr Quaternion a(Vector3(1.0f, 2.0f, 3.0f)); CORRADE_COMPARE(a, Quaternion({1.0f, 2.0f, 3.0f}, 0.0f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void QuaternionTest::constructCopy() { From 407071dc9658bbac62184731d95bc5b3c929700b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Mar 2013 23:27:16 +0100 Subject: [PATCH 09/11] Math: test also possibility of Unit implicit conversions. --- src/Math/Test/AngleTest.cpp | 5 +++-- src/Math/Test/UnitTest.cpp | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Math/Test/AngleTest.cpp b/src/Math/Test/AngleTest.cpp index 1feba3aa8..cdc3b3eba 100644 --- a/src/Math/Test/AngleTest.cpp +++ b/src/Math/Test/AngleTest.cpp @@ -128,10 +128,11 @@ void AngleTest::literals() { } void AngleTest::conversion() { - constexpr Deg a(Rad(1.57079633f)); + /* Implicit conversion should be allowed */ + constexpr Deg a = Rad(1.57079633f); CORRADE_COMPARE(Float(a), 90.0f); - constexpr Rad b(Deg(90.0f)); + constexpr Rad b = Deg(90.0f); CORRADE_COMPARE(Float(b), 1.57079633f); } diff --git a/src/Math/Test/UnitTest.cpp b/src/Math/Test/UnitTest.cpp index 1951fd127..805b0a4b1 100644 --- a/src/Math/Test/UnitTest.cpp +++ b/src/Math/Test/UnitTest.cpp @@ -64,6 +64,10 @@ inline Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, Sec val void UnitTest::construct() { constexpr Sec a(25.0f); CORRADE_COMPARE(Float(a), 25.0f); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); + CORRADE_VERIFY(!(std::is_convertible::value)); } void UnitTest::constructDefault() { @@ -75,6 +79,9 @@ void UnitTest::constructConversion() { constexpr Seci a(25.0); constexpr Sec b(a); CORRADE_COMPARE(b, Sec(25.0f)); + + /* Implicit conversion is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); } void UnitTest::compare() { From cdcb37cd0c4e893deb738e3382fd56c9c0048e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 22 Mar 2013 16:04:42 +0100 Subject: [PATCH 10/11] Platform: better way to specify application configuration. Each implementation of *Application::Configuration will have different methods tailored to feature set of the underlying toolkit. Currently each windowed application's Configuration has only window title (except NaClApplication) and window size. WindowlessGlxApplication has empty class. More features will come later. Also created introductionary documentation for Platform namespace. --- doc/platform.dox | 144 +++++++++++++++++++++- src/Platform/AbstractXApplication.cpp | 22 +++- src/Platform/AbstractXApplication.h | 76 +++++++++++- src/Platform/GlutApplication.cpp | 25 +++- src/Platform/GlutApplication.h | 89 +++++++++++-- src/Platform/GlxApplication.h | 16 +-- src/Platform/NaClApplication.cpp | 23 +++- src/Platform/NaClApplication.h | 59 ++++++++- src/Platform/Sdl2Application.cpp | 24 +++- src/Platform/Sdl2Application.h | 81 +++++++++--- src/Platform/WindowlessGlxApplication.cpp | 15 +++ src/Platform/WindowlessGlxApplication.h | 36 ++++-- src/Platform/XEglApplication.h | 16 +-- 13 files changed, 542 insertions(+), 84 deletions(-) diff --git a/doc/platform.dox b/doc/platform.dox index 15e664c7c..e74aaaeb3 100644 --- a/doc/platform.dox +++ b/doc/platform.dox @@ -22,14 +22,152 @@ DEALINGS IN THE SOFTWARE. */ -namespace Magnum { +namespace Magnum { namespace Platform { /** @page platform Platform support @brief Integration into windowing toolkits and creation of windowless contexts @tableofcontents -@todoc write when the API is stabilized +Platform namespace provides classes integrating %Magnum engine into various +toolkits, both windowed and windowless. All the classes have common API to +achieve static polymorphism, so basically you can use different toolkits on +different platforms and the only thing you need to change is the class name, +everything else is the same. -*/ +Basic usage is to subclass the chosen `*Application` class and implement +required methods. + +@section platform-windowed Windowed applications + +Windowed applications provide a window and keyboard and mouse handling. The +most basic toolkit (and toolkit available on most platforms) is GLUT, which is +is implemented in GlutApplication. As said above, the usage is similar for all +toolkits, you must provide two-argument constructor and implement at least +@ref GlutApplication::viewportEvent() "viewportEvent()" and +@ref GlutApplication::drawEvent() "drawEvent()". + +Barebone application implementation which will just clear the window to dark +blue color: +@code +#include +#include +#include + +using namespace Magnum; + +class MyApplication: public Platform::GlutApplication { + public: + MyApplication(int& argc, char** argv); + + void viewportEvent(const Vector2i& viewport) override; + void drawEvent() override; +}; + +MyApplication::MyApplication(int& argc, char** argv): Platform::GlutApplication(argc, argv) { + // Set clear color to dark blue + Renderer::setClearColor({0.0f, 0.0f, 0.4f}); +} + +void MyApplication::viewportEvent(const Vector2i& size) { + // Resize the framebuffer to new window size + defaultFramebuffer.setViewport({{}, size}); +} + +void MyApplication::drawEvent() { + // Clear the window + defaultFramebuffer.clear(); + + // The context is double-buffered, swap buffers + swapBuffers(); +} + +// main() function implementation +MAGNUM_GLUTAPPLICATION_MAIN(MyApplication) +@endcode + +@section platform-windowless Windowless applications + +Windowless applications provide just a context for ofscreen rendering or +performing tasks on GPU. There is not yet any platform-independent toolkit +which could handle this in portable way, thus you have to use platform-specific +ones. As example we use WindowlessGlxApplication, you need to implement just +@ref WindowlessGlxApplication::exec() "exec()" function. + +Barebone application which will just print out current OpenGL version and +renderer string and exits: +@code +#include +#include + +using namespace Magnum; + +class MyApplication: public Platform::WindowlessGlxApplication { + public: + MyApplication(int& argc, char** argv); + + int exec() override; +}; + +MyApplication::MyApplication(int& argc, char** argv): Platform::WindowlessGlxApplication(argc, argv) {} + +int MyApplication::exec() { + Debug() << "OpenGL version:" << Context::current()->versionString(); + Debug() << "OpenGL renderer:" << Context::current()->rendererString(); + + // Exit with success + return 0; } + +// main() function implementation +MAGNUM_WINDOWLESSGLXAPPLICATION_MAIN(MyApplication) +@endcode + +@section platform-compilation Compilation with CMake + +Barebone compilation consists just of finding %Magnum library with required +`*Application` component, compilation of the executable and linking the +libraries to it: +@code +find_package(Magnum REQUIRED GlutApplication) + +include_directories(${MAGNUM_INCLUDE_DIRS}) + +add_executable(myapplication MyApplication.cpp) +target_link_libraries(myapplication + ${MAGNUM_LIBRARIES} + ${MAGNUM_GLUTAPPLICATION_LIBRARIES}) +@endcode + +@section platform-configuration Specifying configuration + +By default the application is created with some reasonable defaults (e.g. +window size 800x600 pixels). If you want something else, you can pass +@ref GlutApplication::Configuration "Configuration" instance to application +constructor. Using method chaining it can be done conveniently like this: +@code +MyApplication::MyApplication(int& argc, char** argv): + Platform::GlutApplication(argc, argv, (new Configuration()) + ->setTitle("My Application")->setSize({800, 600}) { + // ... +} +@endcode + +However, sometimes you would need to configure the application based on some +configuration file or system introspection. In that case you can pass `nullptr` +instead of Configuration instance and then specify it later with +@ref GlutApplication::createContext() "createContext()": +@code +MyApplication::MyApplication(int& argc, char** argv): Platform::GlutApplication(argc, argv, nullptr) { + // ... + + createContext((new Configuration()) + ->setTitle("My Application") + ->setSize(size)); + + // ... +} +@endcode + +*/ +}} diff --git a/src/Platform/AbstractXApplication.cpp b/src/Platform/AbstractXApplication.cpp index 37aa4fcc1..7442c6e85 100644 --- a/src/Platform/AbstractXApplication.cpp +++ b/src/Platform/AbstractXApplication.cpp @@ -36,7 +36,19 @@ namespace Magnum { namespace Platform { -AbstractXApplication::AbstractXApplication(AbstractContextHandler* contextHandler, int&, char**, const std::string& title, const Vector2i& size): contextHandler(contextHandler), viewportSize(size), flags(Flag::Redraw) { +AbstractXApplication::AbstractXApplication(AbstractContextHandler* contextHandler, int&, char**): contextHandler(contextHandler), flags(Flag::Redraw) { + createContext(new Configuration); +} + +AbstractXApplication::AbstractXApplication(AbstractContextHandler* contextHandler, int&, char**, Configuration* configuration): contextHandler(contextHandler), flags(Flag::Redraw) { + if(configuration) createContext(configuration); +} + +void AbstractXApplication::createContext(AbstractXApplication::Configuration* configuration) { + CORRADE_ASSERT(!c, "AbstractXApplication::createContext(): context already created", ); + + viewportSize = configuration->size(); + /* Get default X display */ display = XOpenDisplay(0); @@ -61,8 +73,8 @@ AbstractXApplication::AbstractXApplication(AbstractContextHandlervisual, AllocNone); attr.event_mask = 0; unsigned long mask = CWBackPixel|CWBorderPixel|CWColormap|CWEventMask; - window = XCreateWindow(display, root, 20, 20, size.x(), size.y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); - XSetStandardProperties(display, window, title.c_str(), 0, None, 0, 0, 0); + window = XCreateWindow(display, root, 20, 20, configuration->size().x(), configuration->size().y(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); + XSetStandardProperties(display, window, configuration->title().c_str(), 0, None, 0, 0, 0); XFree(visInfo); /* Be notified about closing the window */ @@ -82,6 +94,7 @@ AbstractXApplication::AbstractXApplication(AbstractContextHandlerexperimentalExtensionWranglerFeatures()); c = new Context; + delete configuration; } AbstractXApplication::~AbstractXApplication() { @@ -152,4 +165,7 @@ int AbstractXApplication::exec() { return 0; } +AbstractXApplication::Configuration::Configuration(): _title("Magnum X Application"), _size(800, 600) {} +AbstractXApplication::Configuration::~Configuration() = default; + }} diff --git a/src/Platform/AbstractXApplication.h b/src/Platform/AbstractXApplication.h index 04fdad3c6..f3af833a1 100644 --- a/src/Platform/AbstractXApplication.h +++ b/src/Platform/AbstractXApplication.h @@ -50,28 +50,40 @@ namespace Platform { /** @nosubgrouping @brief Base for X11-based applications -Supports keyboard and mouse handling. - +Supports keyboard and mouse handling. See @ref platform for brief introduction. @note Not meant to be used directly, see subclasses. */ class AbstractXApplication { public: + class Configuration; class InputEvent; class KeyEvent; class MouseEvent; class MouseMoveEvent; + /** + * @brief Default constructor + * @param contextHandler OpenGL context handler + * @param argc Count of arguments of `main()` function + * @param argv Arguments of `main()` function + * + * Creates application with default configuration. See Configuration + * for more information. + */ + explicit AbstractXApplication(AbstractContextHandler* contextHandler, int& argc, char** argv); + /** * @brief Constructor * @param contextHandler OpenGL context handler * @param argc Count of arguments of `main()` function * @param argv Arguments of `main()` function - * @param title Window title - * @param size Window size + * @param configuration Configuration * - * Creates window with double-buffered OpenGL ES 2 context. + * The @p configuration is deleted afterwards. If `nullptr` is passed + * as @p configuration, the context is not created and must be created + * with createContext(). */ - explicit AbstractXApplication(AbstractContextHandler* contextHandler, int& argc, char** argv, const std::string& title = "Magnum X application", const Vector2i& size = Vector2i(800, 600)); + explicit AbstractXApplication(AbstractContextHandler* contextHandler, int& argc, char** argv, Configuration* configuration); /** * @brief Destructor @@ -90,6 +102,9 @@ class AbstractXApplication { inline void exit() { flags |= Flag::Exit; } protected: + /** @copydoc GlutApplication::createContext() */ + void createContext(Configuration* configuration); + /** @{ @name Drawing functions */ /** @copydoc GlutApplication::viewportEvent() */ @@ -154,6 +169,55 @@ class AbstractXApplication { CORRADE_ENUMSET_OPERATORS(AbstractXApplication::Flags) +/** +@brief %Configuration + +Double-buffered OpenGL context. +@see AbstractXApplication(), createContext() +*/ +class AbstractXApplication::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + explicit Configuration(); + ~Configuration(); + + /** @brief Window title */ + inline std::string title() const { return _title; } + + /** + * @brief Set window title + * @return Pointer to self (for method chaining) + * + * Default is `"Magnum X Application"`. + */ + inline Configuration* setTitle(std::string title) { + _title = std::move(title); + return this; + } + + /** @brief Window size */ + inline Vector2i size() const { return _size; } + + /** + * @brief Set window size + * @return Pointer to self (for method chaining) + * + * Default is `{800, 600}`. + */ + inline Configuration* setSize(const Vector2i& size) { + _size = size; + return this; + } + + private: + std::string _title; + Vector2i _size; +}; + /** @brief Base for input events diff --git a/src/Platform/GlutApplication.cpp b/src/Platform/GlutApplication.cpp index cdf7dd5c9..2aa125759 100644 --- a/src/Platform/GlutApplication.cpp +++ b/src/Platform/GlutApplication.cpp @@ -31,16 +31,31 @@ namespace Magnum { namespace Platform { GlutApplication* GlutApplication::instance = nullptr; -GlutApplication::GlutApplication(int& argc, char** argv, const std::string& title, const Vector2i& size) { +GlutApplication::GlutApplication(int& argc, char** argv): c(nullptr) { + initialize(argc, argv); + createContext(new Configuration); +} + +GlutApplication::GlutApplication(int& argc, char** argv, Configuration* configuration): c(nullptr) { + initialize(argc, argv); + if(configuration) createContext(configuration); +} + +void GlutApplication::initialize(int& argc, char** argv) { /* Save global instance */ instance = this; /* Init GLUT */ glutInit(&argc, argv); +} + +void GlutApplication::createContext(Configuration* configuration) { + CORRADE_ASSERT(!c, "GlutApplication::createContext(): context already created", ); + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH|GLUT_STENCIL); - glutInitWindowSize(size.x(), size.y()); - glutCreateWindow(title.c_str()); + glutInitWindowSize(configuration->size().x(), configuration->size().y()); + glutCreateWindow(configuration->title().c_str()); glutReshapeFunc(staticViewportEvent); glutSpecialFunc(staticKeyEvent); glutMouseFunc(staticMouseEvent); @@ -50,6 +65,7 @@ GlutApplication::GlutApplication(int& argc, char** argv, const std::string& titl ExtensionWrangler::initialize(); c = new Context; + delete configuration; } GlutApplication::~GlutApplication() { @@ -74,4 +90,7 @@ void GlutApplication::staticMouseMoveEvent(int x, int y) { instance->mouseMoveEvent(e); } +GlutApplication::Configuration::Configuration(): _title("Magnum GLUT Application"), _size(800, 600) {} +GlutApplication::Configuration::~Configuration() = default; + }} diff --git a/src/Platform/GlutApplication.h b/src/Platform/GlutApplication.h index ccf90113a..861376044 100644 --- a/src/Platform/GlutApplication.h +++ b/src/Platform/GlutApplication.h @@ -45,9 +45,9 @@ namespace Platform { /** @nosubgrouping @brief GLUT application -Creates double-buffered RGBA window with depth and stencil buffers. Supports -keyboard handling for limited subset of keys, mouse handling with support for -changing cursor and mouse tracking and warping. +Supports keyboard handling for limited subset of keys, mouse handling with +support for changing cursor and mouse tracking and warping. See @ref platform +for brief introduction. @section GlutApplication-usage Usage @@ -67,19 +67,33 @@ to simplify porting. */ class GlutApplication { public: + class Configuration; class InputEvent; class KeyEvent; class MouseEvent; class MouseMoveEvent; /** - * @brief Constructor + * @brief Default constructor * @param argc Count of arguments of `main()` function * @param argv Arguments of `main()` function - * @param title Window title - * @param size Window size + * + * Creates application with default configuration. See Configuration + * for more information. */ - explicit GlutApplication(int& argc, char** argv, const std::string& title = "Magnum GLUT application", const Vector2i& size = Vector2i(800, 600)); + explicit GlutApplication(int& argc, char** argv); + + /** + * @brief Constructor + * @param argc Count of arguments of `main()` function + * @param argv Arguments of `main()` function + * @param configuration Configuration + * + * The @p configuration is deleted afterwards. If `nullptr` is passed + * as @p configuration, the context is not created and must be created + * with createContext(). + */ + explicit GlutApplication(int& argc, char** argv, Configuration* configuration); virtual ~GlutApplication(); @@ -92,9 +106,17 @@ class GlutApplication { return 0; } + protected: + /** + * @brief Create context with given configuration + * + * The @p configuration is deleted afterwards. Must be called if and + * only if the context wasn't created by the constructor itself. + */ + void createContext(Configuration* configuration); + /** @{ @name Drawing functions */ - protected: /** * @brief Viewport event * @@ -209,6 +231,8 @@ class GlutApplication { /*@}*/ private: + void initialize(int& argc, char** argv); + inline static void staticViewportEvent(int x, int y) { instance->viewportEvent({x, y}); } @@ -228,6 +252,55 @@ class GlutApplication { Context* c; }; +/** +@brief %Configuration + +Double-buffered RGBA window with depth and stencil buffers. +@see GlutApplication(), createContext() +*/ +class GlutApplication::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + explicit Configuration(); + ~Configuration(); + + /** @brief Window title */ + inline std::string title() const { return _title; } + + /** + * @brief Set window title + * @return Pointer to self (for method chaining) + * + * Default is `"Magnum GLUT Application"`. + */ + inline Configuration* setTitle(std::string title) { + _title = std::move(title); + return this; + } + + /** @brief Window size */ + inline Vector2i size() const { return _size; } + + /** + * @brief Set window size + * @return Pointer to self (for method chaining) + * + * Default is `{800, 600}`. + */ + inline Configuration* setSize(const Vector2i& size) { + _size = size; + return this; + } + + private: + std::string _title; + Vector2i _size; +}; + /** @brief Base for input events diff --git a/src/Platform/GlxApplication.h b/src/Platform/GlxApplication.h index 4984ad6f1..c5a28ac71 100644 --- a/src/Platform/GlxApplication.h +++ b/src/Platform/GlxApplication.h @@ -36,8 +36,7 @@ namespace Magnum { namespace Platform { /** @brief GLX application -Creates window with double-buffered OpenGL or OpenGL ES 2.0 context, if -targeting OpenGL ES. Uses GlxContextHandler. +Uses GlxContextHandler. See @ref platform for brief introduction. @section GlxApplication-usage Usage @@ -57,14 +56,11 @@ to simplify porting. */ class GlxApplication: public AbstractXApplication { public: - /** - * @brief Constructor - * @param argc Count of arguments of `main()` function - * @param argv Arguments of `main()` function - * @param title Window title - * @param size Window size - */ - inline explicit GlxApplication(int& argc, char** argv, const std::string& title = "Magnum GLX application", const Vector2i& size = Vector2i(800, 600)): AbstractXApplication(new GlxContextHandler, argc, argv, title, size) {} + /** @copydoc GlutApplication::GlutApplication(int&, char**) */ + inline explicit GlxApplication(int& argc, char** argv): AbstractXApplication(new GlxContextHandler, argc, argv) {} + + /** @copydoc GlutApplication::GlutApplication(int&, char**, Configuration*) */ + inline explicit GlxApplication(int& argc, char** argv, Configuration* configuration): AbstractXApplication(new GlxContextHandler, argc, argv, configuration) {} }; /** @hideinitializer diff --git a/src/Platform/NaClApplication.cpp b/src/Platform/NaClApplication.cpp index 87a442ccc..d746f1aa1 100644 --- a/src/Platform/NaClApplication.cpp +++ b/src/Platform/NaClApplication.cpp @@ -32,15 +32,27 @@ namespace Magnum { namespace Platform { -NaClApplication::NaClApplication(PP_Instance instance, const Vector2i& size): Instance(instance), Graphics3DClient(this), MouseLock(this), viewportSize(size) { +NaClApplication::NaClApplication(PP_Instance instance): Instance(instance), Graphics3DClient(this), MouseLock(this), c(nullptr) { + createContext(new Configuration); +} + +NaClApplication::NaClApplication(PP_Instance instance, Configuration* configuration): Instance(instance), Graphics3DClient(this), MouseLock(this), c(nullptr) { + if(configuration) createContext(configuration); +} + +void NaClApplication::createContext(NaClApplication::Configuration* configuration) { + CORRADE_ASSERT(!c, "NaClApplication::createContext(): context already created", ); + + viewportSize = configuration->size(); + std::int32_t attributes[] = { PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8, PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24, PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8, PP_GRAPHICS3DATTRIB_SAMPLES, 0, PP_GRAPHICS3DATTRIB_SAMPLE_BUFFERS, 0, - PP_GRAPHICS3DATTRIB_WIDTH, size.x(), - PP_GRAPHICS3DATTRIB_HEIGHT, size.y(), + PP_GRAPHICS3DATTRIB_WIDTH, configuration->size().x(), + PP_GRAPHICS3DATTRIB_HEIGHT, configuration->size().y(), PP_GRAPHICS3DATTRIB_NONE }; @@ -66,6 +78,8 @@ NaClApplication::NaClApplication(PP_Instance instance, const Vector2i& size): In /* Make sure viewportEvent() is called for first time */ flags |= Flag::ViewportUpdated; + + delete configuration; } NaClApplication::~NaClApplication() { @@ -209,4 +223,7 @@ void NaClApplication::mouseLockCallback(void* applicationInstance, std::int32_t) instance->flags |= Flag::MouseLocked; } +NaClApplication::Configuration::Configuration(): _size(640, 480) {} +NaClApplication::Configuration::~Configuration() = default; + }} diff --git a/src/Platform/NaClApplication.h b/src/Platform/NaClApplication.h index 7ba5aa39d..2772bee12 100644 --- a/src/Platform/NaClApplication.h +++ b/src/Platform/NaClApplication.h @@ -53,8 +53,7 @@ namespace Magnum { namespace Platform { @brief NaCl application Application running in [Google Chrome Native Client](https://developers.google.com/native-client/). -Creates double-buffered RGBA canvas with depth and stencil buffers. Supports -keyboard and mouse handling. +Supports keyboard and mouse handling. See @ref platform for brief introduction. @section NaClApplication-usage Usage @@ -74,17 +73,31 @@ to simplify porting. */ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public pp::MouseLock { public: + class Configuration; class InputEvent; class KeyEvent; class MouseEvent; class MouseMoveEvent; /** - * @brief Constructor + * @brief Default constructor * @param instance Module instance - * @param size Rendering size + * + * Creates application with default configuration. See Configuration + * for more information. */ - explicit NaClApplication(PP_Instance instance, const Vector2i& size = Vector2i(640, 480)); + explicit NaClApplication(PP_Instance instance); + + /** + * @brief Constructor + * @param instance Module instance + * @param configuration Configuration + * + * The @p configuration is deleted afterwards. If `nullptr` is passed + * as @p configuration, the context is not created and must be created + * with createContext(). + */ + explicit NaClApplication(PP_Instance instance, Configuration* configuration); ~NaClApplication(); @@ -102,6 +115,8 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public bool setFullscreen(bool enabled); protected: + /** @copydoc GlutApplication::createContext() */ + void createContext(Configuration* configuration); /** @{ @name Drawing functions */ @@ -223,6 +238,40 @@ class NaClApplication: public pp::Instance, public pp::Graphics3DClient, public CORRADE_ENUMSET_FRIEND_OPERATORS(Flags) }; +/** +@brief %Configuration + +Double-buffered RGBA canvas with depth and stencil buffers. +@see NaClApplication(), createContext() +*/ +class NaClApplication::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + explicit Configuration(); + ~Configuration(); + + /** @brief Window size */ + inline Vector2i size() const { return _size; } + + /** + * @brief Set window size + * @return Pointer to self (for method chaining) + * + * Default is `{640, 480}`. + */ + inline Configuration* setSize(const Vector2i& size) { + _size = size; + return this; + } + + private: + Vector2i _size; +}; + /** @brief Base for input events diff --git a/src/Platform/Sdl2Application.cpp b/src/Platform/Sdl2Application.cpp index 6ed239158..9a39d9251 100644 --- a/src/Platform/Sdl2Application.cpp +++ b/src/Platform/Sdl2Application.cpp @@ -49,7 +49,17 @@ Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) { } -Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Vector2i& size): flags(Flag::Redraw) { +Sdl2Application::Sdl2Application(int&, char**): context(nullptr), flags(Flag::Redraw) { + createContext(new Configuration); +} + +Sdl2Application::Sdl2Application(int&, char**, Configuration* configuration): context(nullptr), flags(Flag::Redraw) { + if(configuration) createContext(configuration); +} + +void Sdl2Application::createContext(Configuration* configuration) { + CORRADE_ASSERT(!context, "Sdl2Application::createContext(): context already created", ); + if(SDL_Init(SDL_INIT_VIDEO) < 0) { Error() << "Cannot initialize SDL."; std::exit(1); @@ -59,8 +69,8 @@ Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Vec SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - window = SDL_CreateWindow(name.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - size.x(), size.y(), SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); + window = SDL_CreateWindow(configuration->title().c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + configuration->size().x(), configuration->size().y(), SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); if(!window) { Error() << "Cannot create window."; std::exit(2); @@ -76,11 +86,12 @@ Sdl2Application::Sdl2Application(int, char**, const std::string& name, const Vec SDL_Event* sizeEvent = new SDL_Event; sizeEvent->type = SDL_WINDOWEVENT; sizeEvent->window.event = SDL_WINDOWEVENT_RESIZED; - sizeEvent->window.data1 = size.x(); - sizeEvent->window.data2 = size.y(); + sizeEvent->window.data1 = configuration->size().x(); + sizeEvent->window.data2 = configuration->size().y(); SDL_PushEvent(sizeEvent); c = new Context; + delete configuration; } Sdl2Application::~Sdl2Application() { @@ -150,6 +161,9 @@ void Sdl2Application::setMouseLocked(bool enabled) { SDL_SetRelativeMouseMode(enabled ? SDL_TRUE : SDL_FALSE); } +Sdl2Application::Configuration::Configuration(): _title("Magnum SDL2 Application"), _size(800, 600) {} +Sdl2Application::Configuration::~Configuration() = default; + Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseEvent::modifiers() { if(modifiersLoaded) return _modifiers; modifiersLoaded = true; diff --git a/src/Platform/Sdl2Application.h b/src/Platform/Sdl2Application.h index 356b5109d..9f36b90c4 100644 --- a/src/Platform/Sdl2Application.h +++ b/src/Platform/Sdl2Application.h @@ -47,9 +47,8 @@ namespace Platform { /** @nosubgrouping @brief SDL2 application -Application using [Simple DirectMedia Layer](www.libsdl.org/). Centered -non-resizable window with double-buffered OpenGL context and 24bit depth -buffer. Supports keyboard and mouse handling. +Application using [Simple DirectMedia Layer](www.libsdl.org/). Supports +keyboard and mouse handling. See @ref platform for brief introduction. @section Sdl2Application-usage Usage @@ -69,37 +68,29 @@ to simplify porting. */ class Sdl2Application { public: + class Configuration; class InputEvent; class KeyEvent; class MouseEvent; class MouseMoveEvent; - /** - * @brief Constructor - * @param argc Count of arguments of `main()` function - * @param argv Arguments of `main()` function - * @param title Window title - * @param size Window size - */ - explicit Sdl2Application(int argc, char** argv, const std::string& title = "Magnum SDL2 application", const Vector2i& size = Vector2i(800, 600)); + /** @copydoc GlutApplication::GlutApplication(int&, char**) */ + explicit Sdl2Application(int& argc, char** argv); + + /** @copydoc GlutApplication::GlutApplication(int&, char**, Configuration*) */ + explicit Sdl2Application(int& argc, char** argv, Configuration* configuration); - /** - * @brief Destructor - * - * Deletes context and destroys the window. - */ virtual ~Sdl2Application(); - /** - * @brief Execute main loop - * @return Value for returning from `main()`. - */ + /** @copydoc GlutApplication::exec() */ int exec(); /** @brief Exit application main loop */ inline void exit() { flags |= Flag::Exit; } protected: + /** @copydoc GlutApplication::createContext() */ + void createContext(Configuration* configuration); /** @{ @name Drawing functions */ @@ -183,6 +174,56 @@ class Sdl2Application { CORRADE_ENUMSET_OPERATORS(Sdl2Application::Flags) +/** +@brief %Configuration + +Centered non-resizable window with double-buffered OpenGL context and 24bit +depth buffer. +@see Sdl2Application(), createContext() +*/ +class Sdl2Application::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + explicit Configuration(); + ~Configuration(); + + /** @brief Window title */ + inline std::string title() const { return _title; } + + /** + * @brief Set window title + * @return Pointer to self (for method chaining) + * + * Default is `"Magnum SDL2 Application"`. + */ + inline Configuration* setTitle(std::string title) { + _title = std::move(title); + return this; + } + + /** @brief Window size */ + inline Vector2i size() const { return _size; } + + /** + * @brief Set window size + * @return Pointer to self (for method chaining) + * + * Default is `{800, 600}`. + */ + inline Configuration* setSize(const Vector2i& size) { + _size = size; + return this; + } + + private: + std::string _title; + Vector2i _size; +}; + /** @brief Base for input events diff --git a/src/Platform/WindowlessGlxApplication.cpp b/src/Platform/WindowlessGlxApplication.cpp index 36370c686..12429ab20 100644 --- a/src/Platform/WindowlessGlxApplication.cpp +++ b/src/Platform/WindowlessGlxApplication.cpp @@ -24,6 +24,7 @@ #include "WindowlessGlxApplication.h" +#include #include #include "Context.h" @@ -33,6 +34,16 @@ namespace Magnum { namespace Platform { WindowlessGlxApplication::WindowlessGlxApplication(int&, char**) { + createContext(new Configuration); +} + +WindowlessGlxApplication::WindowlessGlxApplication(int&, char**, Configuration* configuration) { + if(configuration) createContext(configuration); +} + +void WindowlessGlxApplication::createContext(Configuration* configuration) { + CORRADE_ASSERT(!c, "WindowlessGlxApplication::createContext(): context already created", ); + display = XOpenDisplay(nullptr); /* Check version */ @@ -89,6 +100,7 @@ WindowlessGlxApplication::WindowlessGlxApplication(int&, char**) { ExtensionWrangler::initialize(ExtensionWrangler::ExperimentalFeatures::Enable); c = new Context; + delete configuration; } WindowlessGlxApplication::~WindowlessGlxApplication() { @@ -96,4 +108,7 @@ WindowlessGlxApplication::~WindowlessGlxApplication() { glXDestroyContext(display, context); } +WindowlessGlxApplication::Configuration::Configuration() = default; +WindowlessGlxApplication::Configuration::~Configuration() = default; + }} diff --git a/src/Platform/WindowlessGlxApplication.h b/src/Platform/WindowlessGlxApplication.h index 47c0cbced..4e0762ccc 100644 --- a/src/Platform/WindowlessGlxApplication.h +++ b/src/Platform/WindowlessGlxApplication.h @@ -45,6 +45,8 @@ namespace Magnum { namespace Platform { /** @brief Windowless GLX application +See @ref platform for brief introduction. + @section WindowlessGlxApplication-usage Usage Place your code into exec(). The subclass can be then used directly in @@ -62,16 +64,14 @@ If no other application header is included this class is also aliased to */ class WindowlessGlxApplication { public: - /** - * @brief Constructor - * @param argc Count of arguments of `main()` function - * @param argv Arguments of `main()` function - * - * Creates window with double-buffered OpenGL 3.2 core context or - * OpenGL ES 2.0 context, if targeting OpenGL ES. - */ + class Configuration; + + /** @copydoc GlutApplication::GlutApplication(int&, char**) */ explicit WindowlessGlxApplication(int& argc, char** argv); + /** @copydoc GlutApplication::GlutApplication(int&, char**, Configuration*) */ + explicit WindowlessGlxApplication(int& argc, char** argv, Configuration* configuration); + ~WindowlessGlxApplication(); /** @@ -80,6 +80,10 @@ class WindowlessGlxApplication { */ virtual int exec() = 0; + protected: + /** @copydoc GlutApplication::createContext() */ + void createContext(Configuration* configuration); + private: Display* display; GLXContext context; @@ -88,6 +92,22 @@ class WindowlessGlxApplication { Context* c; }; +/** +@brief %Configuration + +@see WindowlessGlxApplication(), createContext() +*/ +class WindowlessGlxApplication::Configuration { + Configuration(const Configuration&) = delete; + Configuration(Configuration&&) = delete; + Configuration& operator=(const Configuration&) = delete; + Configuration& operator=(Configuration&&) = delete; + + public: + explicit Configuration(); + ~Configuration(); +}; + /** @hideinitializer @brief Entry point for windowless GLX application @param className Class name diff --git a/src/Platform/XEglApplication.h b/src/Platform/XEglApplication.h index 65cc2d5ae..f9c716b27 100644 --- a/src/Platform/XEglApplication.h +++ b/src/Platform/XEglApplication.h @@ -36,8 +36,7 @@ namespace Magnum { namespace Platform { /** @brief X/EGL application -Creates window with double-buffered OpenGL ES 2 context. Uses -EglContextHandler. +Uses EglContextHandler. See @ref platform for brief introduction. @section XEglApplication-usage Usage @@ -57,14 +56,11 @@ to simplify porting. */ class XEglApplication: public AbstractXApplication { public: - /** - * @brief Constructor - * @param argc Count of arguments of `main()` function - * @param argv Arguments of `main()` function - * @param title Window title - * @param size Window size - */ - inline explicit XEglApplication(int& argc, char** argv, const std::string& title = "Magnum X/EGL application", const Vector2i& size = Vector2i(800, 600)): AbstractXApplication(new EglContextHandler, argc, argv, title, size) {} + /** @copydoc GlutApplication::GlutApplication(int&, char**) */ + inline explicit XEglApplication(int& argc, char** argv): AbstractXApplication(new EglContextHandler, argc, argv) {} + + /** @copydoc GlutApplication::GlutApplication(int&, char**, Configuration*) */ + inline explicit XEglApplication(int& argc, char** argv, Configuration* configuration): AbstractXApplication(new EglContextHandler, argc, argv, configuration) {} }; /** @hideinitializer From 9121902c7326a1f363bb57f3832d62c9304d83bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 22 Mar 2013 17:22:39 +0100 Subject: [PATCH 11/11] Minor documentation fixes. --- doc/scenegraph.dox | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/doc/scenegraph.dox b/doc/scenegraph.dox index 6588fe109..d634c0188 100644 --- a/doc/scenegraph.dox +++ b/doc/scenegraph.dox @@ -85,10 +85,10 @@ Parent object can be either passed in constructor or using Object::setParent(). Scene3D scene; Object3D* first = new Object3D(&scene); -Object3D* second = new Object3D(&first); +Object3D* second = new Object3D(first); @endcode -Object3D children can be accessed using Object::firstChild() and +%Object children can be accessed using Object::firstChild() and Object::lastChild(), then you can traverse siblings (objects with the same parent) with Object::previousSibling() and Object::nextSibling(). For example all children of an object can be traversed the following way: @@ -149,22 +149,20 @@ implement needed functions in your own Object subclass without having to subclass each feature individually (and making the code overly verbose). Simplified example: @code -class Bomb: public Object3D, Drawable, Animatable { +class Bomb: public Object3D, SceneGraph::Drawable3D<>, SceneGraph:.Animable3D<> { public: - inline Bomb(Object3D* parent): Object3D(parent), Drawable(this), Animatable(this) {} + inline Bomb(Object3D* parent): Object3D(parent), SceneGraph::Drawable3D<>(this), SceneGraph::Animable3D<>(this) {} protected: - void draw() { - // drawing implementation for Drawable feature - } + // drawing implementation for Drawable feature + void draw() override; - void animationStep() { - // animation step for Animatable feature - } + // animation step for Animable feature + void animationStep() override; }; @endcode -From the outside there is no difference between features added as member and +From the outside there is no difference between features added "at runtime" and features added using multiple inheritance, they can be both accessed from feature list. @@ -197,9 +195,9 @@ it first, because by default the caching is disabled. You can enable it using AbstractFeature::setCachedTransformations() and then implement corresponding cleaning function(s): @code -class CachingObject: public Object3D, Object3D::FeatureType { +class CachingObject: public Object3D, SceneGraph::AbstractFeature3D<> { public: - CachingObject(Object3D* parent): Object3D::FeatureType(this) { + CachingObject(Object3D* parent): SceneGraph::AbstractFeature3D<>(this) { setCachedTransformations(CachedTransformation::Absolute); } @@ -262,7 +260,7 @@ inherited after the %Object class: @code class MyObject: public Object3D, MyFeature { public: - inline MyObject(Object3D* parent): Object3D(parent), MyFeature(this) {} + MyObject(Object3D* parent): Object3D(parent), MyFeature(this) {} }; @endcode When constructing MyObject, Object3D constructor is called first and then @@ -275,7 +273,7 @@ However, if we would inherit MyFeature first, it will cause problems: @code class MyObject: MyFeature, public Object3D { public: - inline MyObject(Object3D* parent): MyFeature(this), Object3D(parent) {} // crash! + MyObject(Object3D* parent): MyFeature(this), Object3D(parent) {} // crash! }; @endcode MyFeature tries to add itself to feature list in not-yet-constructed Object3D, @@ -287,7 +285,7 @@ wouldn't help either: @code class MyObject: MyFeature, public Object3D { public: - inline MyObject(Object3D* parent): Object3D(parent), MyFeature(this) {} + MyObject(Object3D* parent): Object3D(parent), MyFeature(this) {} // crash on destruction! };