diff --git a/doc/changelog.dox b/doc/changelog.dox index 24f04742a..15763d611 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -210,6 +210,7 @@ See also: @ref Primitives::coneSolid(), @ref Primitives::cylinderSolid(), @ref Primitives::grid3DSolid(), @ref Primitives::planeSolid() and @ref Primitives::uvSphereSolid() can now have tangents as well +- Added @ref Primitives::icosphereWireframe() @subsubsection changelog-latest-new-scenegraph SceneGraph library diff --git a/doc/generated/primitives.cpp b/doc/generated/primitives.cpp index 166253984..7f1bb57a9 100644 --- a/doc/generated/primitives.cpp +++ b/doc/generated/primitives.cpp @@ -108,6 +108,7 @@ struct PrimitiveVisualizer: Platform::WindowlessApplication { std::pair cubeWireframe(); std::pair cylinderWireframe(); std::pair grid3DWireframe(); + std::pair icosphereWireframe(); std::pair line3D(); std::pair planeWireframe(); std::pair uvSphereWireframe(); @@ -257,6 +258,7 @@ int PrimitiveVisualizer::exec() { &PrimitiveVisualizer::cubeWireframe, &PrimitiveVisualizer::cylinderWireframe, &PrimitiveVisualizer::grid3DWireframe, + &PrimitiveVisualizer::icosphereWireframe, &PrimitiveVisualizer::line3D, &PrimitiveVisualizer::planeWireframe, &PrimitiveVisualizer::uvSphereWireframe}) @@ -497,6 +499,10 @@ std::pair PrimitiveVisualizer::grid3DWireframe() { return {Primitives::grid3DWireframe({5, 3}), "grid3dwireframe.png"}; } +std::pair PrimitiveVisualizer::icosphereWireframe() { + return {Primitives::icosphereWireframe(), "icospherewireframe.png"}; +} + std::pair PrimitiveVisualizer::line3D() { Trade::MeshData line = Primitives::line3D(); MeshTools::transformPointsInPlace(Matrix4::translation(Vector3::xAxis(-1.0f))*Matrix4::scaling(Vector3::xScale(2.0f)), diff --git a/doc/primitives-icospherewireframe.png b/doc/primitives-icospherewireframe.png new file mode 100644 index 000000000..07468a5a9 Binary files /dev/null and b/doc/primitives-icospherewireframe.png differ diff --git a/src/Magnum/Primitives/Icosphere.cpp b/src/Magnum/Primitives/Icosphere.cpp index 7a1f504be..0fd6ff1af 100644 --- a/src/Magnum/Primitives/Icosphere.cpp +++ b/src/Magnum/Primitives/Icosphere.cpp @@ -42,16 +42,19 @@ constexpr UnsignedInt Indices[]{ 3, 4, 5, 4, 3, 8, 6, 5, 11, + 5, 6, 10, 9, 10, 2, 10, 9, 3, 7, 8, 9, 8, 7, 0, + 11, 0, 1, 0, 11, 4, 6, 2, 10, 1, 6, 11, 3, 5, 10, + 5, 4, 11, 2, 7, 9, 7, 1, 0, @@ -59,26 +62,30 @@ constexpr UnsignedInt Indices[]{ 4, 8, 0 }; -constexpr Vector3 Positions[]{ - {0.0f, -0.525731f, 0.850651f}, - {0.850651f, 0.0f, 0.525731f}, - {0.850651f, 0.0f, -0.525731f}, - {-0.850651f, 0.0f, -0.525731f}, - {-0.850651f, 0.0f, 0.525731f}, - {-0.525731f, 0.850651f, 0.0f}, - {0.525731f, 0.850651f, 0.0f}, - {0.525731f, -0.850651f, 0.0f}, - {-0.525731f, -0.850651f, 0.0f}, - {0.0f, -0.525731f, -0.850651f}, - {0.0f, 0.525731f, -0.850651f}, - {0.0f, 0.525731f, 0.850651f} +/* Can't be just an array of Vector3 because MSVC 2015 is special. See + Crosshair.cpp for details. */ +constexpr struct VertexSolidStrip { + Vector3 position; +} Vertices[]{ + {{0.0f, -0.525731f, 0.850651f}}, + {{0.850651f, 0.0f, 0.525731f}}, + {{0.850651f, 0.0f, -0.525731f}}, + {{-0.850651f, 0.0f, -0.525731f}}, + {{-0.850651f, 0.0f, 0.525731f}}, + {{-0.525731f, 0.850651f, 0.0f}}, + {{0.525731f, 0.850651f, 0.0f}}, + {{0.525731f, -0.850651f, 0.0f}}, + {{-0.525731f, -0.850651f, 0.0f}}, + {{0.0f, -0.525731f, -0.850651f}}, + {{0.0f, 0.525731f, -0.850651f}}, + {{0.0f, 0.525731f, 0.850651f}} }; } Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) { const std::size_t indexCount = Containers::arraySize(Indices)*(1 << subdivisions*2); - const std::size_t vertexCount = Containers::arraySize(Positions) + ((indexCount - Containers::arraySize(Indices))/3); + const std::size_t vertexCount = Containers::arraySize(Vertices) + ((indexCount - Containers::arraySize(Indices))/3); Containers::Array indexData{indexCount*sizeof(UnsignedInt)}; auto indices = Containers::arrayCast(indexData); @@ -96,12 +103,12 @@ Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) { { auto vertices = Containers::arrayCast(vertexData); Containers::StridedArrayView1D positions{vertices, &vertices[0].position, vertices.size(), sizeof(Vertex)}; - for(std::size_t i = 0; i != Containers::arraySize(Positions); ++i) - positions[i] = Positions[i]; + for(std::size_t i = 0; i != Containers::arraySize(Vertices); ++i) + positions[i] = Vertices[i].position; for(std::size_t i = 0; i != subdivisions; ++i) { const std::size_t iterationIndexCount = Containers::arraySize(Indices)*(1 << (i + 1)*2); - const std::size_t iterationVertexCount = Containers::arraySize(Positions) + ((iterationIndexCount - Containers::arraySize(Indices))/3); + const std::size_t iterationVertexCount = Containers::arraySize(Vertices) + ((iterationIndexCount - Containers::arraySize(Indices))/3); MeshTools::subdivideInPlace(indices.prefix(iterationIndexCount), positions.prefix(iterationVertexCount), [](const Vector3& a, const Vector3& b) { return (a+b).normalized(); }); @@ -125,4 +132,39 @@ Trade::MeshData icosphereSolid(const UnsignedInt subdivisions) { Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normals}}}; } +namespace { + +/* Taking the above, converting each triangle to three lines and leaving out + the duplicates. Because each edge is shared by two triangles and there was + 20 triangles to begin with, there's 30 edges. */ +constexpr UnsignedInt IndicesWireframe[]{ + 1, 2, 2, 6, 6, 1, + 1, 7, 7, 2, + 3, 4, 4, 5, 5, 3, + 3, 8, 8, 4, + 6, 5, 5, 11, 11, 6, + + 6, 10, 10, 5, + 9, 10, 10, 2, 2, 9, + 9, 3, 3, 10, + 7, 8, 8, 9, 9, 7, + 7, 0, 0, 8, + + 11, 0, 0, 1, 1, 11, + 11, 4, 4, 0 +}; +constexpr Trade::MeshAttributeData AttributesWireframe[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, + Containers::stridedArrayView(Vertices, &Vertices[0].position, + Containers::arraySize(Vertices), sizeof(Vector3))} +}; + +} + +Trade::MeshData icosphereWireframe() { + return Trade::MeshData{MeshPrimitive::Lines, + {}, IndicesWireframe, Trade::MeshIndexData{IndicesWireframe}, + {}, Vertices, Trade::meshAttributeDataNonOwningArray(AttributesWireframe)}; +} + }} diff --git a/src/Magnum/Primitives/Icosphere.h b/src/Magnum/Primitives/Icosphere.h index 6ef178d77..3f4267e07 100644 --- a/src/Magnum/Primitives/Icosphere.h +++ b/src/Magnum/Primitives/Icosphere.h @@ -47,14 +47,29 @@ normals. The @p subdivisions parameter describes how many times is each icosphere triangle subdivided, recursively. Specifying @cpp 0 @ce will result in an -icosphere with 20 faces, saying @cpp 1 @ce will result in an icosphere with 80 -faces (each triangle subdivided into four smaller), saying @cpp 2 @ce will -result in 320 faces and so on. In particular, this is different from the -`subdivisions` parameter in @ref grid3DSolid() or @ref grid3DWireframe(). +icosphere with 12 vertices and 20 faces, saying @cpp 1 @ce will result in an +icosphere with 80 faces (each triangle subdivided into four smaller), saying +@cpp 2 @ce will result in 320 faces and so on. In particular, this is different +from the `subdivisions` parameter in @ref grid3DSolid() or @ref grid3DWireframe(). @see @ref uvSphereSolid(), @ref uvSphereWireframe() */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData icosphereSolid(UnsignedInt subdivisions); +/** +@brief Wireframe 3D icosphere +@m_since_latest + +Sphere of radius @cpp 1.0f @ce with 12 vertices and 30 edges, centered at +origin. @ref MeshPrimitive::Lines with @ref MeshIndexType::UnsignedShort +indices and @ref VertexFormat::Vector3 positions. The returned instance +references data stored in constant memory. + +@image html primitives-icospherewireframe.png width=256px + +@see @ref icosphereWireframe() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData icosphereWireframe(); + }} #endif diff --git a/src/Magnum/Primitives/Test/IcosphereTest.cpp b/src/Magnum/Primitives/Test/IcosphereTest.cpp index 87f59ca96..b6fd6b4b9 100644 --- a/src/Magnum/Primitives/Test/IcosphereTest.cpp +++ b/src/Magnum/Primitives/Test/IcosphereTest.cpp @@ -38,12 +38,16 @@ struct IcosphereTest: TestSuite::Tester { void count0(); void data1(); void count2(); + + void wireframe(); }; IcosphereTest::IcosphereTest() { addTests({&IcosphereTest::count0, &IcosphereTest::data1, - &IcosphereTest::count2}); + &IcosphereTest::count2, + + &IcosphereTest::wireframe}); } void IcosphereTest::count0() { @@ -146,6 +150,16 @@ void IcosphereTest::count2() { CORRADE_COMPARE(icosphere.attributeCount(), 2); } +void IcosphereTest::wireframe() { + Trade::MeshData icosphere = Primitives::icosphereWireframe(); + + CORRADE_COMPARE(icosphere.primitive(), MeshPrimitive::Lines); + CORRADE_VERIFY(icosphere.isIndexed()); + CORRADE_COMPARE(icosphere.indexCount(), 60); + CORRADE_COMPARE(icosphere.vertexCount(), 12); + CORRADE_COMPARE(icosphere.attributeCount(), 1); +} + }}}} CORRADE_TEST_MAIN(Magnum::Primitives::Test::IcosphereTest)