From 06b82755ad5b952b10da1a7dc0d9992e159e2e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 7 Mar 2020 19:48:11 +0100 Subject: [PATCH] Primitives: use compile-time attribute definitions where possible. Now possible in all cases, except for grid, where the combination count is too large to be practical, even more so with the introduction of tangents in the future. --- src/Magnum/Primitives/Circle.cpp | 87 +++++++++++++------ src/Magnum/Primitives/Grid.cpp | 15 +++- .../Primitives/Implementation/Spheroid.cpp | 50 ++++++----- .../Implementation/WireframeSpheroid.cpp | 13 ++- 4 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/Magnum/Primitives/Circle.cpp b/src/Magnum/Primitives/Circle.cpp index 61ddb4665..9086eea9b 100644 --- a/src/Magnum/Primitives/Circle.cpp +++ b/src/Magnum/Primitives/Circle.cpp @@ -32,26 +32,39 @@ namespace Magnum { namespace Primitives { +namespace { + +constexpr Trade::MeshAttributeData AttributeData2D[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, + 0, 0, sizeof(Vector2)} +}; + +constexpr Trade::MeshAttributeData AttributeData2DTextureCoords[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, + 0, 0, 2*sizeof(Vector2)}, + Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, + sizeof(Vector2), 0, 2*sizeof(Vector2)} +}; + +} + Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoords textureCoords) { CORRADE_ASSERT(segments >= 3, "Primitives::circle2DSolid(): segments must be >= 3", (Trade::MeshData{MeshPrimitive::TriangleFan, 0})); /* Allocate interleaved array for all vertex data */ - std::size_t stride = sizeof(Vector2); - std::size_t attributeCount = 1; - if(textureCoords == CircleTextureCoords::Generate) { - ++attributeCount; - stride += sizeof(Vector2); - } + Containers::Array attributes; + if(textureCoords == CircleTextureCoords::Generate) + attributes = Trade::meshAttributeDataNonOwningArray(AttributeData2DTextureCoords); + else + attributes = Trade::meshAttributeDataNonOwningArray(AttributeData2D); + const std::size_t stride = attributes[0].stride(); Containers::Array vertexData{stride*(segments + 2)}; - Containers::Array attributes{attributeCount}; /* Fill positions */ Containers::StridedArrayView1D positions{vertexData, reinterpret_cast(vertexData.begin()), segments + 2, std::ptrdiff_t(stride)}; - attributes[0] = - Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}; positions[0] = {}; /* Points on the circle. The first/last point is here twice to close the circle properly. */ @@ -67,13 +80,11 @@ Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoo Containers::StridedArrayView1D textureCoords{vertexData, reinterpret_cast(vertexData.begin() + sizeof(Vector2)), positions.size(), std::ptrdiff_t(stride)}; - attributes[1] = - Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, textureCoords}; for(std::size_t i = 0; i != positions.size(); ++i) textureCoords[i] = positions[i]*0.5f + Vector2{0.5f}; } - return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes)}; + return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes), UnsignedInt(positions.size())}; } Trade::MeshData circle2DWireframe(const UnsignedInt segments) { @@ -91,7 +102,33 @@ Trade::MeshData circle2DWireframe(const UnsignedInt segments) { positions[i] = {sincos.second, sincos.first}; } - return Trade::MeshData{MeshPrimitive::LineLoop, std::move(vertexData), {Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}}}; + return Trade::MeshData{MeshPrimitive::LineLoop, std::move(vertexData), + Trade::meshAttributeDataNonOwningArray(AttributeData2D), UnsignedInt(positions.size())}; +} + +namespace { + +constexpr Trade::MeshAttributeData AttributeData3D[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + 0, 0, 2*sizeof(Vector3)}, + Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, + sizeof(Vector3), 0, 2*sizeof(Vector3)} +}; + +constexpr Trade::MeshAttributeData AttributeData3DTextureCoords[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + 0, 0, 2*sizeof(Vector3) + sizeof(Vector2)}, + Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, + sizeof(Vector3), 0, 2*sizeof(Vector3) + sizeof(Vector2)}, + Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, + 2*sizeof(Vector3), 0, 2*sizeof(Vector3) + sizeof(Vector2)} +}; + +constexpr Trade::MeshAttributeData AttributeData3DWireframe[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + 0, 0, sizeof(Vector3)} +}; + } Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords textureCoords) { @@ -99,21 +136,18 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords te (Trade::MeshData{MeshPrimitive::TriangleFan, 0})); /* Allocate interleaved array for all vertex data */ - std::size_t stride = 2*sizeof(Vector3); - std::size_t attributeCount = 2; - if(textureCoords == CircleTextureCoords::Generate) { - ++attributeCount; - stride += sizeof(Vector2); - } + Containers::Array attributes; + if(textureCoords == CircleTextureCoords::Generate) + attributes = Trade::meshAttributeDataNonOwningArray(AttributeData3DTextureCoords); + else + attributes = Trade::meshAttributeDataNonOwningArray(AttributeData3D); + const std::size_t stride = attributes[0].stride(); Containers::Array vertexData{stride*(segments + 2)}; - Containers::Array attributes{attributeCount}; /* Fill positions */ Containers::StridedArrayView1D positions{vertexData, reinterpret_cast(vertexData.begin()), segments + 2, std::ptrdiff_t(stride)}; - attributes[0] = - Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}; positions[0] = {}; /* Points on the circle. The first/last point is here twice to close the circle properly. */ @@ -128,8 +162,6 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords te Containers::StridedArrayView1D normals{vertexData, reinterpret_cast(vertexData.begin() + sizeof(Vector3)), segments + 2, std::ptrdiff_t(stride)}; - attributes[1] = - Trade::MeshAttributeData{Trade::MeshAttribute::Normal, normals}; for(Vector3& normal: normals) normal = Vector3::zAxis(1.0f); /* Fill texture coords, if any */ @@ -137,13 +169,11 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords te Containers::StridedArrayView1D textureCoords{vertexData, reinterpret_cast(vertexData.begin() + 2*sizeof(Vector3)), positions.size(), std::ptrdiff_t(stride)}; - attributes[2] = - Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, textureCoords}; for(std::size_t i = 0; i != positions.size(); ++i) textureCoords[i] = positions[i].xy()*0.5f + Vector2{0.5f}; } - return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes)}; + return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes), UnsignedInt(positions.size())}; } Trade::MeshData circle3DWireframe(const UnsignedInt segments) { @@ -161,7 +191,8 @@ Trade::MeshData circle3DWireframe(const UnsignedInt segments) { positions[i] = {sincos.second, sincos.first, 0.0f}; } - return Trade::MeshData{MeshPrimitive::LineLoop, std::move(vertexData), {Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}}}; + return Trade::MeshData{MeshPrimitive::LineLoop, std::move(vertexData), + Trade::meshAttributeDataNonOwningArray(AttributeData3DWireframe), UnsignedInt(positions.size())}; } }} diff --git a/src/Magnum/Primitives/Grid.cpp b/src/Magnum/Primitives/Grid.cpp index d85262df8..68f434710 100644 --- a/src/Magnum/Primitives/Grid.cpp +++ b/src/Magnum/Primitives/Grid.cpp @@ -109,11 +109,22 @@ Trade::MeshData grid3DSolid(const Vector2i& subdivisions, const GridFlags flags) textureCoords[i] = positions[i].xy()*0.5f + Vector2{0.5f}; } + /* Not using a compile-time attribute array because there's way too many + combinations */ return Trade::MeshData{MeshPrimitive::Triangles, std::move(indexData), Trade::MeshIndexData{indices}, std::move(vertexData), std::move(attributes)}; } +namespace { + +constexpr Trade::MeshAttributeData AttributeData3DWireframe[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + 0, 0, sizeof(Vector3)} +}; + +} + Trade::MeshData grid3DWireframe(const Vector2i& subdivisions) { const Vector2i vertexCount = subdivisions + Vector2i{2}; const Vector2i faceCount = subdivisions + Vector2i{1}; @@ -153,7 +164,9 @@ Trade::MeshData grid3DWireframe(const Vector2i& subdivisions) { return Trade::MeshData{MeshPrimitive::Lines, std::move(indexData), Trade::MeshIndexData{indices}, - std::move(vertexData), {Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}}}; + std::move(vertexData), + Trade::meshAttributeDataNonOwningArray(AttributeData3DWireframe), + UnsignedInt(vertexCount.product())}; } }} diff --git a/src/Magnum/Primitives/Implementation/Spheroid.cpp b/src/Magnum/Primitives/Implementation/Spheroid.cpp index 8c8d31e39..377ce59ca 100644 --- a/src/Magnum/Primitives/Implementation/Spheroid.cpp +++ b/src/Magnum/Primitives/Implementation/Spheroid.cpp @@ -220,37 +220,39 @@ void Spheroid::capVertexRing(Float y, Float textureCoordsV, const Vector3& norma } } -Trade::MeshData Spheroid::finalize() { - Trade::MeshIndexData indices{_indexData}; +namespace { + +constexpr Trade::MeshAttributeData AttributeData[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + offsetof(Vertex, position), 0, sizeof(Vertex)}, + Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, + offsetof(Vertex, normal), 0, sizeof(Vertex)} +}; - const std::size_t stride = _textureCoords == TextureCoords::Generate ? - sizeof(VertexTextureCoords) : sizeof(Vertex); - const std::size_t size = _vertexData.size()/stride; +constexpr Trade::MeshAttributeData AttributeDataTextureCoords[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + offsetof(VertexTextureCoords, position), 0, sizeof(VertexTextureCoords)}, + Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, + offsetof(VertexTextureCoords, normal), 0, sizeof(VertexTextureCoords)}, + Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, + offsetof(VertexTextureCoords, textureCoords), 0, sizeof(VertexTextureCoords)} +}; - auto typedVertices = reinterpret_cast(_vertexData.data()); - Trade::MeshAttributeData positions{Trade::MeshAttribute::Position, - /* GCC 4.8 needs the arrayView() */ - Containers::stridedArrayView(Containers::arrayView(_vertexData), - &typedVertices[0].position, size, stride)}; - Trade::MeshAttributeData normals{Trade::MeshAttribute::Normal, - /* GCC 4.8 needs the arrayView() */ - Containers::stridedArrayView(Containers::arrayView(_vertexData), - &typedVertices[0].normal, size, stride)}; +} + +Trade::MeshData Spheroid::finalize() { + Trade::MeshIndexData indices{_indexData}; Containers::Array attributes; - if(_textureCoords == TextureCoords::Generate) { - Trade::MeshAttributeData textureCoords{Trade::MeshAttribute::TextureCoordinates, - /* GCC 4.8 needs the arrayView() */ - Containers::stridedArrayView(Containers::arrayView(_vertexData), - &typedVertices[0].textureCoords, size, stride)}; - attributes = Containers::Array{Containers::InPlaceInit, {positions, normals, textureCoords}}; - } else { - attributes = Containers::Array{Containers::InPlaceInit, {positions, normals}}; - } + if(_textureCoords == TextureCoords::Generate) + attributes = Trade::meshAttributeDataNonOwningArray(AttributeDataTextureCoords); + else + attributes = Trade::meshAttributeDataNonOwningArray(AttributeData); + const UnsignedInt vertexCount = _vertexData.size()/attributes[0].stride(); return Trade::MeshData{MeshPrimitive::Triangles, Containers::arrayAllocatorCast(std::move(_indexData)), indices, - std::move(_vertexData), std::move(attributes)}; + std::move(_vertexData), std::move(attributes), vertexCount}; } }}} diff --git a/src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp b/src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp index 6b40ca3aa..29212b416 100644 --- a/src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp +++ b/src/Magnum/Primitives/Implementation/WireframeSpheroid.cpp @@ -124,12 +124,23 @@ void WireframeSpheroid::cylinder() { arrayAppend(_indexData, {UnsignedInt(_vertexData.size()) - 4*_segments + i, UnsignedInt(_vertexData.size()) + i}); } +namespace { + +constexpr Trade::MeshAttributeData AttributeData[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, + 0, 0, sizeof(Vector3)} +}; + +} + Trade::MeshData WireframeSpheroid::finalize() { Trade::MeshIndexData indices{_indexData}; Trade::MeshAttributeData positions{Trade::MeshAttribute::Position, Containers::arrayView(_vertexData)}; + const UnsignedInt vertexCount = _vertexData.size(); return Trade::MeshData{MeshPrimitive::Lines, Containers::arrayAllocatorCast(std::move(_indexData)), indices, - Containers::arrayAllocatorCast(std::move(_vertexData)), {positions}}; + Containers::arrayAllocatorCast(std::move(_vertexData)), + Trade::meshAttributeDataNonOwningArray(AttributeData), vertexCount}; } }}}