diff --git a/doc/changelog.dox b/doc/changelog.dox index 6df21d496..f0a9017e3 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -207,6 +207,11 @@ See also: bootstrap project for using Magnum together with wxWidgets (see [mosra/magnum-bootstrap#19](https://github.com/mosra/magnum-bootstrap/pull/19)) +@subsubsection changelog-latest-new-primitives Primitives library + +- @ref Primitives::circle2DSolid() and @ref Primitives::circle3DSolid() + can now generate a textured mesh + @subsubsection changelog-latest-new-scenegraph SceneGraph library - Added @ref SceneGraph::AbstractObject::Type / diff --git a/src/Magnum/Primitives/Circle.cpp b/src/Magnum/Primitives/Circle.cpp index 63254f9ac..d38df8ded 100644 --- a/src/Magnum/Primitives/Circle.cpp +++ b/src/Magnum/Primitives/Circle.cpp @@ -33,15 +33,21 @@ namespace Magnum { namespace Primitives { -Trade::MeshData2D circle2DSolid(const UnsignedInt segments) { +Trade::MeshData2D circle2DSolid(const UnsignedInt segments, CircleTextureCoords textureCoords) { CORRADE_ASSERT(segments >= 3, "Primitives::circle2DSolid(): segments must be >= 3", (Trade::MeshData2D{MeshPrimitive::TriangleFan, {}, {}, {}, {}, nullptr})); std::vector positions; positions.reserve(segments + 2); + std::vector> textureCoordinates; + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.emplace_back(); + /* Central point */ positions.emplace_back(); + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.front().emplace_back(0.5f, 0.5f); /* Points on circle. The first/last point is here twice to close the circle properly. */ @@ -49,10 +55,14 @@ Trade::MeshData2D circle2DSolid(const UnsignedInt segments) { for(UnsignedInt i = 0; i != segments + 1; ++i) { const Rad angle(Float(i)*angleIncrement); const std::pair sincos = Math::sincos(angle); - positions.emplace_back(sincos.second, sincos.first); + Vector2 position{sincos.second, sincos.first}; + positions.emplace_back(position); + + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.front().emplace_back(position*0.5f + Vector2{0.5f}); } - return Trade::MeshData2D{MeshPrimitive::TriangleFan, {}, {std::move(positions)}, {}, {}, nullptr}; + return Trade::MeshData2D{MeshPrimitive::TriangleFan, {}, {std::move(positions)}, std::move(textureCoordinates), {}, nullptr}; } Trade::MeshData2D circle2DWireframe(const UnsignedInt segments) { @@ -73,15 +83,21 @@ Trade::MeshData2D circle2DWireframe(const UnsignedInt segments) { return Trade::MeshData2D{MeshPrimitive::LineLoop, {}, {std::move(positions)}, {}, {}, nullptr}; } -Trade::MeshData3D circle3DSolid(const UnsignedInt segments) { +Trade::MeshData3D circle3DSolid(const UnsignedInt segments, CircleTextureCoords textureCoords) { CORRADE_ASSERT(segments >= 3, "Primitives::circle3DSolid(): segments must be >= 3", (Trade::MeshData3D{MeshPrimitive::TriangleFan, {}, {}, {}, {}, {}, nullptr})); std::vector positions; positions.reserve(segments + 2); + std::vector> textureCoordinates; + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.emplace_back(); + /* Central point */ positions.emplace_back(); + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.front().emplace_back(0.5f, 0.5f); /* Points on circle. The first/last point is here twice to close the circle properly. */ @@ -89,13 +105,17 @@ Trade::MeshData3D circle3DSolid(const UnsignedInt segments) { for(UnsignedInt i = 0; i != segments + 1; ++i) { const Rad angle(Float(i)*angleIncrement); const std::pair sincos = Math::sincos(angle); - positions.emplace_back(sincos.second, sincos.first, 0.0f); + Vector3 position{sincos.second, sincos.first, 0.0f}; + positions.emplace_back(position); + + if(textureCoords == CircleTextureCoords::Generate) + textureCoordinates.front().emplace_back(position.xy()*0.5f + Vector2{0.5f}); } /* Normals. All pointing in the same direction. */ std::vector normals{segments + 2, Vector3::zAxis(1.0f)}; - return Trade::MeshData3D{MeshPrimitive::TriangleFan, {}, {std::move(positions)}, {std::move(normals)}, {}, {}, nullptr}; + return Trade::MeshData3D{MeshPrimitive::TriangleFan, {}, {std::move(positions)}, {std::move(normals)}, std::move(textureCoordinates), {}, nullptr}; } Trade::MeshData3D circle3DWireframe(const UnsignedInt segments) { diff --git a/src/Magnum/Primitives/Circle.h b/src/Magnum/Primitives/Circle.h index e484f09a2..7a671f7ec 100644 --- a/src/Magnum/Primitives/Circle.h +++ b/src/Magnum/Primitives/Circle.h @@ -34,9 +34,21 @@ namespace Magnum { namespace Primitives { +/** +@brief Whether to generate circle texture coordinates + +@see @ref circle2DSolid(), @ref circle3DSolid() +*/ +enum class CircleTextureCoords: UnsignedByte { + DontGenerate, /**< Don't generate texture coordinates */ + Generate /**< Generate texture coordinates */ +}; + /** @brief Solid 2D circle -@param segments Number of segments. Must be greater or equal to @cpp 3 @ce. +@param segments Number of segments. Must be greater or equal to + @cpp 3 @ce. +@param textureCoords Whether to generate texture coordinates Circle with radius @cpp 1.0f @ce. Non-indexed @ref MeshPrimitive::TriangleFan. @@ -44,11 +56,12 @@ Circle with radius @cpp 1.0f @ce. Non-indexed @ref MeshPrimitive::TriangleFan. @see @ref circle2DWireframe(), @ref circle3DSolid() */ -MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D circle2DSolid(UnsignedInt segments); +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D circle2DSolid(UnsignedInt segments, CircleTextureCoords textureCoords = CircleTextureCoords::DontGenerate); /** @brief Wireframe 2D circle -@param segments Number of segments. Must be greater or equal to @cpp 3 @ce. +@param segments Number of segments. Must be greater or equal to + @cpp 3 @ce. Circle with radius @cpp 1.0f @ce. Non-indexed @ref MeshPrimitive::LineLoop. @@ -60,7 +73,9 @@ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData2D circle2DWireframe(UnsignedInt segment /** @brief Solid 3D circle -@param segments Number of segments. Must be greater or equal to @cpp 3 @ce. +@param segments Number of segments. Must be greater or equal to + @cpp 3 @ce. +@param textureCoords Whether to generate texture coordinates Circle on the XY plane with radius @cpp 1.0f @ce. Non-indexed @ref MeshPrimitive::TriangleFan with normals in positive Z direction. @@ -69,7 +84,7 @@ Circle on the XY plane with radius @cpp 1.0f @ce. Non-indexed @see @ref circle3DWireframe(), @ref circle2DSolid() */ -MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D circle3DSolid(UnsignedInt segments); +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData3D circle3DSolid(UnsignedInt segments, CircleTextureCoords textureCoords = CircleTextureCoords::DontGenerate); /** @brief Wireframe 3D circle diff --git a/src/Magnum/Primitives/Test/CircleTest.cpp b/src/Magnum/Primitives/Test/CircleTest.cpp index 44aa21f34..92dda4a6c 100644 --- a/src/Magnum/Primitives/Test/CircleTest.cpp +++ b/src/Magnum/Primitives/Test/CircleTest.cpp @@ -38,14 +38,22 @@ struct CircleTest: TestSuite::Tester { explicit CircleTest(); void solid2D(); + void solid2DTextureCoords(); + void solid3D(); + void solid3DTextureCoords(); + void wireframe2D(); void wireframe3D(); }; CircleTest::CircleTest() { addTests({&CircleTest::solid2D, + &CircleTest::solid2DTextureCoords, + &CircleTest::solid3D, + &CircleTest::solid3DTextureCoords, + &CircleTest::wireframe2D, &CircleTest::wireframe3D}); } @@ -63,6 +71,31 @@ void CircleTest::solid2D() { { 0.0f, -1.0f}, { Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f}, { 1.0f, 0.0f} }), TestSuite::Compare::Container); + CORRADE_COMPARE(circle.textureCoords2DArrayCount(), 0); +} + +void CircleTest::solid2DTextureCoords() { + Trade::MeshData2D circle = Primitives::circle2DSolid(8, Primitives::CircleTextureCoords::Generate); + + CORRADE_VERIFY(!circle.isIndexed()); + CORRADE_COMPARE(circle.primitive(), MeshPrimitive::TriangleFan); + CORRADE_COMPARE_AS(circle.positions(0), (std::vector{ + { 0.0f, 0.0f}, + { 1.0f, 0.0f}, { Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f}, + { 0.0f, 1.0f}, {-Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f}, + {-1.0f, 0.0f}, {-Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f}, + { 0.0f, -1.0f}, { Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f}, + { 1.0f, 0.0f} + }), TestSuite::Compare::Container); + CORRADE_COMPARE(circle.textureCoords2DArrayCount(), 1); + CORRADE_COMPARE_AS(circle.textureCoords2D(0), (std::vector{ + {0.5f, 0.5f}, + {1.0f, 0.5f}, {0.5f + Constants::sqrt2()/4.0f, 0.5f + Constants::sqrt2()/4.0f}, + {0.5f, 1.0f}, {0.5f - Constants::sqrt2()/4.0f, 0.5f + Constants::sqrt2()/4.0f}, + {0.0f, 0.5f}, {0.5f - Constants::sqrt2()/4.0f, 0.5f - Constants::sqrt2()/4.0f}, + {0.5f, 0.0f}, {0.5f + Constants::sqrt2()/4.0f, 0.5f - Constants::sqrt2()/4.0f}, + {1.0f, 0.5f} + }), TestSuite::Compare::Container); } void CircleTest::solid3D() { @@ -90,6 +123,43 @@ void CircleTest::solid3D() { { 0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f, 1.0f} }), TestSuite::Compare::Container); + CORRADE_COMPARE(circle.textureCoords2DArrayCount(), 0); +} + +void CircleTest::solid3DTextureCoords() { + Trade::MeshData3D circle = Primitives::circle3DSolid(8, Primitives::CircleTextureCoords::Generate); + + CORRADE_VERIFY(!circle.isIndexed()); + CORRADE_COMPARE(circle.primitive(), MeshPrimitive::TriangleFan); + CORRADE_COMPARE_AS(circle.positions(0), (std::vector{ + { 0.0f, 0.0f, 0.0f}, + { 1.0f, 0.0f, 0.0f}, { Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f, 0.0f}, + { 0.0f, 1.0f, 0.0f}, {-Constants::sqrt2()/2.0f, Constants::sqrt2()/2.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, {-Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f, 0.0f}, + { 0.0f, -1.0f, 0.0f}, { Constants::sqrt2()/2.0f, -Constants::sqrt2()/2.0f, 0.0f}, + { 1.0f, 0.0f, 0.0f} + }), TestSuite::Compare::Container); + CORRADE_COMPARE_AS(circle.normals(0), (std::vector{ + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f}, + { 0.0f, 0.0f, 1.0f} + }), TestSuite::Compare::Container); + CORRADE_COMPARE(circle.textureCoords2DArrayCount(), 1); + CORRADE_COMPARE_AS(circle.textureCoords2D(0), (std::vector{ + {0.5f, 0.5f}, + {1.0f, 0.5f}, {0.5f + Constants::sqrt2()/4.0f, 0.5f + Constants::sqrt2()/4.0f}, + {0.5f, 1.0f}, {0.5f - Constants::sqrt2()/4.0f, 0.5f + Constants::sqrt2()/4.0f}, + {0.0f, 0.5f}, {0.5f - Constants::sqrt2()/4.0f, 0.5f - Constants::sqrt2()/4.0f}, + {0.5f, 0.0f}, {0.5f + Constants::sqrt2()/4.0f, 0.5f - Constants::sqrt2()/4.0f}, + {1.0f, 0.5f} + }), TestSuite::Compare::Container); } void CircleTest::wireframe2D() {