Browse Source

Primitives: switch to an enum set for texturable primitives.

Making room for GenerateTangents in 3D, and keeping the 2D ones
consistent with 3D. Also renamed GenerateTextureCoords to
GenerateTextureCoordinates in the remaining places to be consistent with
naming in the rest of the APIs.
pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
1b21e4e7ba
  1. 20
      doc/changelog.dox
  2. 4
      doc/generated/shaders.cpp
  3. 16
      src/Magnum/Primitives/Capsule.cpp
  4. 48
      src/Magnum/Primitives/Capsule.h
  5. 30
      src/Magnum/Primitives/Circle.cpp
  6. 90
      src/Magnum/Primitives/Circle.h
  7. 4
      src/Magnum/Primitives/Cone.cpp
  8. 19
      src/Magnum/Primitives/Cone.h
  9. 4
      src/Magnum/Primitives/Cylinder.cpp
  10. 18
      src/Magnum/Primitives/Cylinder.h
  11. 8
      src/Magnum/Primitives/Grid.cpp
  12. 30
      src/Magnum/Primitives/Grid.h
  13. 32
      src/Magnum/Primitives/Implementation/Spheroid.cpp
  14. 13
      src/Magnum/Primitives/Implementation/Spheroid.h
  15. 21
      src/Magnum/Primitives/Plane.cpp
  16. 43
      src/Magnum/Primitives/Plane.h
  17. 21
      src/Magnum/Primitives/Square.cpp
  18. 43
      src/Magnum/Primitives/Square.h
  19. 2
      src/Magnum/Primitives/Test/CapsuleTest.cpp
  20. 4
      src/Magnum/Primitives/Test/CircleTest.cpp
  21. 4
      src/Magnum/Primitives/Test/ConeTest.cpp
  22. 4
      src/Magnum/Primitives/Test/CylinderTest.cpp
  23. 2
      src/Magnum/Primitives/Test/GridTest.cpp
  24. 2
      src/Magnum/Primitives/Test/PlaneTest.cpp
  25. 2
      src/Magnum/Primitives/Test/SquareTest.cpp
  26. 2
      src/Magnum/Primitives/Test/UVSphereTest.cpp
  27. 14
      src/Magnum/Primitives/UVSphere.cpp
  28. 48
      src/Magnum/Primitives/UVSphere.h
  29. 8
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  30. 16
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  31. 12
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  32. 8
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  33. 8
      src/Magnum/Shaders/Test/VertexColorGLTest.cpp

20
doc/changelog.dox

@ -501,6 +501,26 @@ See also:
@ref MeshTools::compressIndices(), @ref MeshTools::duplicate(),
@ref MeshTools::removeDuplicatesInPlace() and @ref MeshTools::subdivide() /
@ref MeshTools::subdivideInPlace() overloads instead
- @cpp Primitives::CapsuleTextureCoords @ce,
@cpp Primitives::CircleTextureCoords @ce,
@cpp Primitives::PlaneTextureCoords @ce,
@cpp Primitives::SquareTextureCoords @ce,
@cpp Primitives::UVSphereTextureCoords @ce enums and
@ref Primitives::capsule3DSolid(), @ref Primitives::circle2DSolid(),
@ref Primitives::circle3DSolid(), @ref Primitives::planeSolid(),
@ref Primitives::squareSolid() and @ref Primitives::uvSphereSolid()
overloads taking those are deprecated in favor of
@ref Primitives::CapsuleFlags, @ref Primitives::Circle2DFlags,
@ref Primitives::Circle3DFlags, @ref Primitives::PlaneFlags,
@ref Primitives::SquareFlags and @ref Primitives::UVSphereFlags
- @cpp Primitives::ConeFlag::GenerateTextureCoords @ce,
@cpp Primitives::CylinderFlag::GenerateTextureCoords @ce,
@cpp Primitives::GridFlag::GenerateTextureCoords @ce and
@cpp Primitives::GridFlag::GenerateNormals @ce is deprecated in favor of
@ref Primitives::ConeFlag::TextureCoordinates,
@ref Primitives::CylinderFlag::TextureCoordinates,
@ref Primitives::GridFlag::TextureCoordinates and
@ref Primitives::GridFlag::Normals for naming consistency
- @cpp Shaders::MeshVisualizer @ce is deprecated as the shader can now handle
both 2D and 3D, use @ref Shaders::MeshVisualizer3D instead
- @cpp Shaders::MeshVisualizer::setTransformationProjectionMatrix() @ce is

4
doc/generated/shaders.cpp

@ -262,7 +262,7 @@ std::string ShaderVisualizer::vector() {
.setColor(BaseColor)
.bindVectorTexture(texture)
.setTransformationProjectionMatrix({})
.draw(MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)));
.draw(MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates)));
GL::Renderer::disable(GL::Renderer::Feature::Blending);
@ -293,7 +293,7 @@ std::string ShaderVisualizer::distanceFieldVector() {
.setOutlineRange(0.6f, 0.4f)
.bindVectorTexture(texture)
.setTransformationProjectionMatrix({})
.draw(MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)));
.draw(MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates)));
GL::Renderer::disable(GL::Renderer::Feature::Blending);

16
src/Magnum/Primitives/Capsule.cpp

@ -98,14 +98,12 @@ Trade::MeshData capsule2DWireframe(const UnsignedInt hemisphereRings, const Unsi
Containers::arrayAllocatorCast<char>(std::move(vertexData)), {positions}};
}
Trade::MeshData capsule3DSolid(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength, const CapsuleTextureCoords textureCoords) {
Trade::MeshData capsule3DSolid(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength, const CapsuleFlags flags) {
CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 3,
"Primitives::capsule3DSolid(): at least one hemisphere ring, one cylinder ring and three segments expected",
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
Implementation::Spheroid capsule(segments, textureCoords == CapsuleTextureCoords::Generate ?
Implementation::Spheroid::TextureCoords::Generate :
Implementation::Spheroid::TextureCoords::DontGenerate);
Implementation::Spheroid capsule{segments, Implementation::Spheroid::Flag(UnsignedByte(flags))};
Float height = 2.0f+2.0f*halfLength;
Float hemisphereTextureCoordsVIncrement = 1.0f/(hemisphereRings*height);
@ -134,6 +132,16 @@ Trade::MeshData capsule3DSolid(const UnsignedInt hemisphereRings, const Unsigned
return capsule.finalize();
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData capsule3DSolid(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength, const CapsuleTextureCoords textureCoords) {
return capsule3DSolid(hemisphereRings, cylinderRings, segments, halfLength,
textureCoords == CapsuleTextureCoords::Generate ?
CapsuleFlag::TextureCoordinates : CapsuleFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Trade::MeshData capsule3DWireframe(const UnsignedInt hemisphereRings, const UnsignedInt cylinderRings, const UnsignedInt segments, const Float halfLength) {
CORRADE_ASSERT(hemisphereRings >= 1 && cylinderRings >= 1 && segments >= 4 && segments%4 == 0,
"Primitives::capsule3DWireframe(): at least one hemisphere and cylinder ring and multiples of 4 segments expected",

48
src/Magnum/Primitives/Capsule.h

@ -29,6 +29,9 @@
* @brief Function @ref Magnum::Primitives::capsule2DWireframe(), @ref Magnum::Primitives::capsule3DSolid(), @ref Magnum::Primitives::capsule3DWireframe()
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Primitives/visibility.h"
#include "Magnum/Trade/Trade.h"
@ -54,15 +57,25 @@ Cylinder of radius @cpp 1.0f @ce along Y axis with hemispheres instead of caps.
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData capsule2DWireframe(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, Float halfLength);
/**
@brief Whether to generate capsule texture coordinates
@brief Capsule flag
@m_since_latest
@see @ref capsule3DSolid()
@see @ref CapsuleFlags, @ref capsule3DSolid()
*/
enum class CapsuleTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
Generate /**< Generate texture coordinates */
enum class CapsuleFlag: UnsignedByte {
TextureCoordinates = 1 << 0 /**< Generate texture coordinates */
};
/**
@brief Capsule flags
@m_since_latest
@see @ref capsule3DSolid()
*/
typedef Containers::EnumSet<CapsuleFlag> CapsuleFlags;
CORRADE_ENUMSET_OPERATORS(CapsuleFlags)
/**
@brief Solid 3D capsule
@param hemisphereRings Number of (face) rings for each hemisphere. Must be
@ -72,7 +85,8 @@ enum class CapsuleTextureCoords: UnsignedByte {
@param segments Number of (face) segments. Must be larger or equal to
@cpp 3 @ce.
@param halfLength Half the length of cylinder part
@param textureCoords Whether to generate texture coordinates
@param flags Flags
@m_since_latest
Cylinder of radius @cpp 1.0f @ce along Y axis with hemispheres instead of caps.
@ref MeshPrimitive::Triangles with @ref MeshIndexType::UnsignedInt indices,
@ -89,7 +103,27 @@ get radius @f$ r @f$, length @f$ l @f$ and preserve correct normals, set
@f$ r @f$, for example using @ref MeshTools::transformPointsInPlace().
@see @ref capsule3DWireframe(), @ref capsule2DWireframe(), @ref cylinderSolid()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData capsule3DSolid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, CapsuleTextureCoords textureCoords = CapsuleTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData capsule3DSolid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, CapsuleFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Whether to generate capsule texture coordinates
@m_deprecated_since_latest Use @ref CapsuleFlags instead.
*/
enum class CORRADE_DEPRECATED_ENUM("use CapsuleFlags instead") CapsuleTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
Generate /**< Generate texture coordinates */
};
/**
@brief @copybrief capsule3DSolid(UnsignedInt, UnsignedInt, UnsignedInt, Float, CapsuleFlags)
@m_deprecated_since_latest Use @ref capsule3DSolid(UnsignedInt, UnsignedInt, UnsignedInt, Float, CapsuleFlags)
instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use capsule3DSolid() with CapsuleFlags instead") Trade::MeshData capsule3DSolid(UnsignedInt hemisphereRings, UnsignedInt cylinderRings, UnsignedInt segments, Float halfLength, CapsuleTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 3D capsule

30
src/Magnum/Primitives/Circle.cpp

@ -48,13 +48,13 @@ constexpr Trade::MeshAttributeData AttributeData2DTextureCoords[]{
}
Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoords textureCoords) {
Trade::MeshData circle2DSolid(const UnsignedInt segments, const Circle2DFlags flags) {
CORRADE_ASSERT(segments >= 3, "Primitives::circle2DSolid(): segments must be >= 3",
(Trade::MeshData{MeshPrimitive::TriangleFan, 0}));
/* Allocate interleaved array for all vertex data */
Containers::Array<Trade::MeshAttributeData> attributes;
if(textureCoords == CircleTextureCoords::Generate)
if(flags & Circle2DFlag::TextureCoordinates)
attributes = Trade::meshAttributeDataNonOwningArray(AttributeData2DTextureCoords);
else
attributes = Trade::meshAttributeDataNonOwningArray(AttributeData2D);
@ -76,7 +76,7 @@ Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoo
}
/* Fill texture coords, if any */
if(textureCoords == CircleTextureCoords::Generate) {
if(flags & Circle2DFlag::TextureCoordinates) {
Containers::StridedArrayView1D<Vector2> textureCoords{vertexData,
reinterpret_cast<Vector2*>(vertexData.begin() + sizeof(Vector2)),
positions.size(), std::ptrdiff_t(stride)};
@ -87,6 +87,15 @@ Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoo
return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes), UnsignedInt(positions.size())};
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData circle2DSolid(const UnsignedInt segments, const CircleTextureCoords textureCoords) {
return circle2DSolid(segments, textureCoords == CircleTextureCoords::Generate ?
Circle2DFlag::TextureCoordinates : Circle2DFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Trade::MeshData circle2DWireframe(const UnsignedInt segments) {
CORRADE_ASSERT(segments >= 3, "Primitives::circle2DWireframe(): segments must be >= 3",
(Trade::MeshData{MeshPrimitive::LineLoop, 0}));
@ -131,13 +140,13 @@ constexpr Trade::MeshAttributeData AttributeData3DWireframe[]{
}
Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords textureCoords) {
Trade::MeshData circle3DSolid(const UnsignedInt segments, const Circle3DFlags flags) {
CORRADE_ASSERT(segments >= 3, "Primitives::circle3DSolid(): segments must be >= 3",
(Trade::MeshData{MeshPrimitive::TriangleFan, 0}));
/* Allocate interleaved array for all vertex data */
Containers::Array<Trade::MeshAttributeData> attributes;
if(textureCoords == CircleTextureCoords::Generate)
if(flags & Circle3DFlag::TextureCoordinates)
attributes = Trade::meshAttributeDataNonOwningArray(AttributeData3DTextureCoords);
else
attributes = Trade::meshAttributeDataNonOwningArray(AttributeData3D);
@ -165,7 +174,7 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords te
for(Vector3& normal: normals) normal = Vector3::zAxis(1.0f);
/* Fill texture coords, if any */
if(textureCoords == CircleTextureCoords::Generate) {
if(flags & Circle3DFlag::TextureCoordinates) {
Containers::StridedArrayView1D<Vector2> textureCoords{vertexData,
reinterpret_cast<Vector2*>(vertexData.begin() + 2*sizeof(Vector3)),
positions.size(), std::ptrdiff_t(stride)};
@ -176,6 +185,15 @@ Trade::MeshData circle3DSolid(const UnsignedInt segments, CircleTextureCoords te
return Trade::MeshData{MeshPrimitive::TriangleFan, std::move(vertexData), std::move(attributes), UnsignedInt(positions.size())};
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData circle3DSolid(const UnsignedInt segments, const CircleTextureCoords textureCoords) {
return circle3DSolid(segments, textureCoords == CircleTextureCoords::Generate ?
Circle3DFlag::TextureCoordinates : Circle3DFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Trade::MeshData circle3DWireframe(const UnsignedInt segments) {
CORRADE_ASSERT(segments >= 3, "Primitives::circle3DWireframe(): segments must be >= 3",
(Trade::MeshData{MeshPrimitive::LineLoop, 0}));

90
src/Magnum/Primitives/Circle.h

@ -29,27 +29,51 @@
* @brief Function @ref Magnum::Primitives::circle2DSolid(), @ref Magnum::Primitives::circle2DWireframe(), @ref Magnum::Primitives::circle3DSolid(), @ref Magnum::Primitives::circle3DWireframe()
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Primitives/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace Primitives {
/**
@brief Whether to generate circle texture coordinates
@m_since{2019,10}
@brief 2D circle flag
@m_since_latest
@see @ref Circle2DFlags, @ref circle2DSolid()
*/
enum class Circle2DFlag: UnsignedByte {
TextureCoordinates = 1 << 0 /**< Generate texture coordinates */
};
/**
@brief 2D circle flags
@m_since_latest
@see @ref circle2DSolid()
*/
typedef Containers::EnumSet<Circle2DFlag> Circle2DFlags;
@see @ref circle2DSolid(), @ref circle3DSolid()
CORRADE_ENUMSET_OPERATORS(Circle2DFlags)
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Whether to generate circle texture coordinates
@m_deprecated_since_latest Use @ref Circle2DFlags or @ref Circle3DFlags
instead.
*/
enum class CircleTextureCoords: UnsignedByte {
enum class CORRADE_DEPRECATED_ENUM("use Circle2DFlags or Circle3DFlags instead") CircleTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
Generate /**< Generate texture coordinates */
};
#endif
/**
@brief Solid 2D circle
@param segments Number of segments. Must be greater or equal to
@cpp 3 @ce.
@param textureCoords Whether to generate texture coordinates
@param segments Number of segments. Must be greater or equal to @cpp 3 @ce.
@param flags Flags
@m_since_latest
Circle with radius @cpp 1.0f @ce. @ref MeshPrimitive::TriangleFan with
@ref MeshIndexType::UnsignedInt indices, interleaved @ref VertexFormat::Vector2
@ -60,7 +84,18 @@ positions and optional @ref VertexFormat::Vector2 texture coordinates.
@see @ref circle2DWireframe(), @ref circle3DSolid(),
@ref MeshTools::generateTriangleFanIndices()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData circle2DSolid(UnsignedInt segments, CircleTextureCoords textureCoords = CircleTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData circle2DSolid(UnsignedInt segments, Circle2DFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief circle2DSolid(UnsignedInt, Circle2DFlags)
@m_deprecated_since_latest Use @ref circle2DSolid(UnsignedInt, Circle2DFlags)
instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use circle2DSolid() with Circle2DFlags instead") Trade::MeshData circle2DSolid(UnsignedInt segments, CircleTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 2D circle
@ -77,11 +112,31 @@ Circle with radius @cpp 1.0f @ce. Non-indexed @ref MeshPrimitive::LineLoop with
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData circle2DWireframe(UnsignedInt segments);
/**
@brief 3D circle flag
@m_since_latest
@see @ref Circle3DFlags, @ref circle3DSolid()
*/
enum class Circle3DFlag: UnsignedByte {
TextureCoordinates = 1 << 0 /**< Generate texture coordinates */
};
/**
@brief 3D circle flags
@m_since_latest
@see @ref circle3DSolid()
*/
typedef Containers::EnumSet<Circle3DFlag> Circle3DFlags;
CORRADE_ENUMSET_OPERATORS(Circle3DFlags)
/**
@brief Solid 3D circle
@param segments Number of segments. Must be greater or equal to
@cpp 3 @ce.
@param textureCoords Whether to generate texture coordinates
@param segments Number of segments. Must be greater or equal to @cpp 3 @ce.
@param flags Flags
@m_since_latest
Circle on the XY plane with radius @cpp 1.0f @ce. Non-indexed
@ref MeshPrimitive::TriangleFan with interleaved @ref VertexFormat::Vector3
@ -93,7 +148,18 @@ optional @ref VertexFormat::Vector2 texture coordinates.
@see @ref circle3DWireframe(), @ref circle2DSolid(),
@ref MeshTools::generateTriangleFanIndices()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData circle3DSolid(UnsignedInt segments, CircleTextureCoords textureCoords = CircleTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData circle3DSolid(UnsignedInt segments, Circle3DFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief circle3DSolid(UnsignedInt, Circle3DFlags)
@m_deprecated_since_latest Use @ref circle3DSolid(UnsignedInt, Circle3DFlags)
instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use circle3DSolid() with Circle2DFlags instead") Trade::MeshData circle3DSolid(UnsignedInt segments, CircleTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 3D circle

4
src/Magnum/Primitives/Cone.cpp

@ -38,7 +38,7 @@ Trade::MeshData coneSolid(const UnsignedInt rings, const UnsignedInt segments, c
"Primitives::coneSolid(): at least one ring and three segments expected",
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
Implementation::Spheroid cone{segments, flags & ConeFlag::GenerateTextureCoords ? Implementation::Spheroid::TextureCoords::Generate : Implementation::Spheroid::TextureCoords::DontGenerate};
Implementation::Spheroid cone{segments, Implementation::Spheroid::Flag(UnsignedByte(flags))};
const Float length = 2.0f*halfLength;
const Float textureCoordsV = flags & ConeFlag::CapEnd ? 1.0f/(length + 1.0f) : 0.0f;
@ -54,7 +54,7 @@ Trade::MeshData coneSolid(const UnsignedInt rings, const UnsignedInt segments, c
/* Faces. Account for the extra vertices for caps and texture coords. */
if(flags & ConeFlag::CapEnd) cone.bottomFaceRing();
if(flags >= (ConeFlag::CapEnd|ConeFlag::GenerateTextureCoords))
if(flags >= (ConeFlag::CapEnd|ConeFlag::TextureCoordinates))
cone.faceRings(rings, 2 + segments);
else if(flags & ConeFlag::CapEnd)
cone.faceRings(rings, 1 + segments);

19
src/Magnum/Primitives/Cone.h

@ -30,6 +30,7 @@
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Magnum.h"
#include "Magnum/Primitives/visibility.h"
@ -42,8 +43,22 @@ namespace Magnum { namespace Primitives {
@see @ref ConeFlags, @ref coneSolid()
*/
enum class ConeFlag {
GenerateTextureCoords = 1 << 0, /**< Generate texture coordinates */
enum class ConeFlag: UnsignedByte {
/**
* Generate texture coordinates
* @m_since_latest
*/
TextureCoordinates = 1 << 0,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Generate texture coordinates
* @m_deprecated_since_latest Use @ref ConeFlag::TextureCoordinates
* instead.
*/
GenerateTextureCoords CORRADE_DEPRECATED_ENUM("use TextureCoordinates instead") = TextureCoordinates,
#endif
CapEnd = 1 << 1 /**< Cap end */
};

4
src/Magnum/Primitives/Cylinder.cpp

@ -38,7 +38,7 @@ Trade::MeshData cylinderSolid(const UnsignedInt rings, const UnsignedInt segment
"Primitives::cylinderSolid(): at least one ring and three segments expected",
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
Implementation::Spheroid cylinder(segments, flags & CylinderFlag::GenerateTextureCoords ? Implementation::Spheroid::TextureCoords::Generate : Implementation::Spheroid::TextureCoords::DontGenerate);
Implementation::Spheroid cylinder{segments, Implementation::Spheroid::Flag(UnsignedByte(flags))};
const Float length = 2.0f*halfLength;
const Float textureCoordsV = flags & CylinderFlag::CapEnds ? 1.0f/(length+2.0f) : 0.0f;
@ -60,7 +60,7 @@ Trade::MeshData cylinderSolid(const UnsignedInt rings, const UnsignedInt segment
/* Faces. Account for the extra vertices for caps and texture coords. */
if(flags & CylinderFlag::CapEnds) cylinder.bottomFaceRing();
if(flags >= (CylinderFlag::CapEnds|CylinderFlag::GenerateTextureCoords))
if(flags >= (CylinderFlag::CapEnds|CylinderFlag::TextureCoordinates))
cylinder.faceRings(rings, 2 + segments);
else if(flags & CylinderFlag::CapEnds)
cylinder.faceRings(rings, 1 + segments);

18
src/Magnum/Primitives/Cylinder.h

@ -42,8 +42,22 @@ namespace Magnum { namespace Primitives {
@see @ref CylinderFlags, @ref cylinderSolid()
*/
enum class CylinderFlag {
GenerateTextureCoords = 1 << 0, /**< Generate texture coordinates */
enum class CylinderFlag: UnsignedByte {
/**
* Generate texture coordinates
* @m_since_latest
*/
TextureCoordinates = 1 << 0,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Generate texture coordinates
* @m_deprecated_since_latest Use @ref CylinderFlag::TextureCoordinates
* instead.
*/
GenerateTextureCoords CORRADE_DEPRECATED_ENUM("use TextureCoordinates instead") = TextureCoordinates,
#endif
CapEnds = 1 << 1 /**< Cap ends */
};

8
src/Magnum/Primitives/Grid.cpp

@ -59,11 +59,11 @@ Trade::MeshData grid3DSolid(const Vector2i& subdivisions, const GridFlags flags)
/* Allocate interleaved array for all vertex data */
std::size_t stride = sizeof(Vector3);
std::size_t attributeCount = 1;
if(flags & GridFlag::GenerateNormals) {
if(flags & GridFlag::Normals) {
++attributeCount;
stride += sizeof(Vector3);
}
if(flags & GridFlag::GenerateTextureCoords) {
if(flags & GridFlag::TextureCoordinates) {
++attributeCount;
stride += sizeof(Vector2);
}
@ -88,7 +88,7 @@ Trade::MeshData grid3DSolid(const Vector2i& subdivisions, const GridFlags flags)
/* Fill normals, if any. It's always the second attribute, right after
positions. */
if(flags & GridFlag::GenerateNormals) {
if(flags & GridFlag::Normals) {
Containers::StridedArrayView1D<Vector3> normals{vertexData,
reinterpret_cast<Vector3*>(vertexData.begin() + attributeOffset),
std::size_t(vertexCount.product()), std::ptrdiff_t(stride)};
@ -98,7 +98,7 @@ Trade::MeshData grid3DSolid(const Vector2i& subdivisions, const GridFlags flags)
for(auto&& i: normals) i = Vector3::zAxis(1.0f);
}
if(flags & GridFlag::GenerateTextureCoords) {
if(flags & GridFlag::TextureCoordinates) {
Containers::StridedArrayView1D<Vector2> textureCoords{vertexData,
reinterpret_cast<Vector2*>(vertexData.begin() + attributeOffset),
std::size_t(vertexCount.product()), std::ptrdiff_t(stride)};

30
src/Magnum/Primitives/Grid.h

@ -44,14 +44,34 @@ namespace Magnum { namespace Primitives {
@see @ref GridFlags, @ref grid3DSolid()
*/
enum class GridFlag: UnsignedByte {
/** Generate texture coordinates with origin in bottom left corner. */
GenerateTextureCoords = 1 << 0,
/**
* Generate texture coordinates with origin in the bottom left corner
* @m_since_latest
*/
TextureCoordinates = 1 << 0,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Generate texture coordinates with origin in the bottom left corner
* @m_deprecated_since_latest Use @ref GridFlag::TextureCoordinates
* instead.
*/
GenerateTextureCoords CORRADE_DEPRECATED_ENUM("use TextureCoordinates instead") = TextureCoordinates,
#endif
/**
* Generate normals inn positive Z direction. Disable if you'd be
* Generate normals in positive Z direction. Disable if you'd be
* generating your own normals anyway (for example based on a heightmap).
*/
GenerateNormals = 1 << 1
Normals = 1 << 1,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Generate normals in positive Z direction.
* @m_deprecated_since_latest Use @ref GridFlag::Normals instead.
*/
GenerateNormals CORRADE_DEPRECATED_ENUM("use Normals instead") = Normals
#endif
};
/**
@ -81,7 +101,7 @@ cells horizontally and 4 vertically. In particular, this is different from the
`subdivisions` parameter in @ref icosphereSolid().
@see @ref grid3DWireframe()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData grid3DSolid(const Vector2i& subdivisions, GridFlags flags = GridFlag::GenerateNormals);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData grid3DSolid(const Vector2i& subdivisions, GridFlags flags = GridFlag::Normals);
/**
@brief Wireframe 3D grid

32
src/Magnum/Primitives/Implementation/Spheroid.cpp

@ -34,7 +34,7 @@
namespace Magnum { namespace Primitives { namespace Implementation {
Spheroid::Spheroid(UnsignedInt segments, TextureCoords textureCoords): _segments(segments), _textureCoords(textureCoords) {}
Spheroid::Spheroid(UnsignedInt segments, Flags flags): _segments(segments), _flags{flags} {}
namespace {
@ -56,7 +56,7 @@ struct VertexTextureCoords {
at the beginning since the growth is optimized for adding a single
element */
void Spheroid::append(const Vector3& position, const Vector3& normal, const Vector2& textureCoords) {
if(_textureCoords == TextureCoords::Generate) {
if(_flags & Flag::TextureCoordinates) {
const VertexTextureCoords v[]{{position, normal, textureCoords}};
arrayAppend(_vertexData, Containers::arrayCast<const char>(Containers::arrayView(v)));
} else {
@ -72,7 +72,7 @@ void Spheroid::setLastVertexTextureCoords(const Vector2& textureCoords) {
void Spheroid::capVertex(Float y, Float normalY, Float textureCoordsV) {
append({0.0f, y, 0.0f}, {0.0f, normalY, 0.0f});
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
setLastVertexTextureCoords({0.5f, textureCoordsV});
}
@ -91,12 +91,12 @@ void Spheroid::hemisphereVertexRings(UnsignedInt count, Float centerY, Rad start
append({x*segmentSinCos.first, centerY+y, z*segmentSinCos.second},
{x*segmentSinCos.first, y, z*segmentSinCos.second});
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
setLastVertexTextureCoords({j*1.0f/_segments, startTextureCoordsV + i*textureCoordsVIncrement});
}
/* Duplicate first segment in the ring for additional vertex for texture coordinate */
if(_textureCoords == TextureCoords::Generate) {
if(_flags & Flag::TextureCoordinates) {
/* This view will become dangling right after append() */
auto typedVertices = Containers::arrayCast<VertexTextureCoords>(_vertexData);
append(typedVertices[typedVertices.size()-_segments].position,
@ -118,12 +118,12 @@ void Spheroid::cylinderVertexRings(const UnsignedInt count, const Float startY,
append({base.x()*segmentSinCos.first, base.y(), base.x()*segmentSinCos.second},
{baseNormal.x()*segmentSinCos.first, baseNormal.y(), baseNormal.x()*segmentSinCos.second});
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
setLastVertexTextureCoords({j*1.0f/_segments, startTextureCoordsV + i*textureCoordsVIncrement});
}
/* Duplicate first segment in the ring for additional vertex for texture coordinate */
if(_textureCoords == TextureCoords::Generate) {
if(_flags & Flag::TextureCoordinates) {
/* This view will become dangling right after append() */
auto typedVertices = Containers::arrayCast<VertexTextureCoords>(_vertexData);
append(typedVertices[typedVertices.size()-_segments].position,
@ -142,7 +142,7 @@ void Spheroid::bottomFaceRing() {
0u,
/* Top right vertex */
(j != _segments-1 || _textureCoords == TextureCoords::Generate) ?
(j != _segments-1 || _flags & Flag::TextureCoordinates) ?
j+2 : 1,
/* Top left vertex */
@ -152,12 +152,12 @@ void Spheroid::bottomFaceRing() {
}
void Spheroid::faceRings(UnsignedInt count, UnsignedInt offset) {
const UnsignedInt vertexSegments = _segments + (_textureCoords == TextureCoords::Generate ? 1 : 0);
const UnsignedInt vertexSegments = _segments + (_flags & Flag::TextureCoordinates ? 1 : 0);
for(UnsignedInt i = 0; i != count; ++i) {
for(UnsignedInt j = 0; j != _segments; ++j) {
const UnsignedInt bottomLeft = i*vertexSegments+j+offset;
const UnsignedInt bottomRight = ((j != _segments-1 || _textureCoords == TextureCoords::Generate) ?
const UnsignedInt bottomRight = ((j != _segments-1 || _flags & Flag::TextureCoordinates) ?
i*vertexSegments+j+1+offset : i*_segments+offset);
const UnsignedInt topLeft = bottomLeft+vertexSegments;
const UnsignedInt topRight = bottomRight+vertexSegments;
@ -175,10 +175,10 @@ void Spheroid::faceRings(UnsignedInt count, UnsignedInt offset) {
}
void Spheroid::topFaceRing() {
const UnsignedInt vertexSegments = _segments + (_textureCoords == TextureCoords::Generate ? 1 : 0);
const UnsignedInt vertexSegments = _segments + (_flags & Flag::TextureCoordinates ? 1 : 0);
UnsignedInt vertexCount;
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
vertexCount = _vertexData.size()/sizeof(VertexTextureCoords);
else
vertexCount = _vertexData.size()/sizeof(Vertex);
@ -189,7 +189,7 @@ void Spheroid::topFaceRing() {
vertexCount - vertexSegments + j - 1,
/* Bottom right vertex */
(j != _segments-1 || _textureCoords == TextureCoords::Generate) ?
(j != _segments-1 || _flags & Flag::TextureCoordinates) ?
vertexCount - vertexSegments + j : vertexCount - _segments - 1,
/* Top vertex */
@ -206,12 +206,12 @@ void Spheroid::capVertexRing(Float y, Float textureCoordsV, const Vector3& norma
const std::pair<Float, Float> segmentSinCos = Math::sincos(segmentAngle);
append({segmentSinCos.first, y, segmentSinCos.second}, normal);
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
setLastVertexTextureCoords({i*1.0f/_segments, textureCoordsV});
}
/* Duplicate first segment in the ring for additional vertex for texture coordinate */
if(_textureCoords == TextureCoords::Generate) {
if(_flags & Flag::TextureCoordinates) {
/* This view will become dangling right after append() */
auto typedVertices = Containers::arrayCast<VertexTextureCoords>(_vertexData);
append(typedVertices[typedVertices.size()-_segments].position,
@ -244,7 +244,7 @@ Trade::MeshData Spheroid::finalize() {
Trade::MeshIndexData indices{_indexData};
Containers::Array<Trade::MeshAttributeData> attributes;
if(_textureCoords == TextureCoords::Generate)
if(_flags & Flag::TextureCoordinates)
attributes = Trade::meshAttributeDataNonOwningArray(AttributeDataTextureCoords);
else
attributes = Trade::meshAttributeDataNonOwningArray(AttributeData);

13
src/Magnum/Primitives/Implementation/Spheroid.h

@ -36,12 +36,13 @@ namespace Magnum { namespace Primitives { namespace Implementation {
class Spheroid {
public:
enum class TextureCoords: UnsignedByte {
DontGenerate,
Generate
enum class Flag: UnsignedByte {
TextureCoordinates = 1 << 0
};
Spheroid(UnsignedInt segments, TextureCoords textureCoords);
typedef Containers::EnumSet<Flag> Flags;
explicit Spheroid(UnsignedInt segments, Flags flags);
void capVertex(Float y, Float normalY, Float textureCoordsV);
void hemisphereVertexRings(UnsignedInt count, Float centerY, Rad startRingAngle, Rad ringAngleIncrement, Float startTextureCoordsV, Float textureCoordsVIncrement);
@ -55,7 +56,7 @@ class Spheroid {
private:
UnsignedInt _segments;
TextureCoords _textureCoords;
Flags _flags;
Containers::Array<UnsignedInt> _indexData;
Containers::Array<char> _vertexData;
@ -64,6 +65,8 @@ class Spheroid {
void setLastVertexTextureCoords(const Vector2& textureCoords);
};
CORRADE_ENUMSET_OPERATORS(Spheroid::Flags)
}}}
#endif

21
src/Magnum/Primitives/Plane.cpp

@ -77,16 +77,25 @@ constexpr Trade::MeshAttributeData AttributesSolidTextureCoords[]{
}
Trade::MeshData planeSolid(const PlaneTextureCoords textureCoords) {
if(textureCoords != PlaneTextureCoords::Generate)
Trade::MeshData planeSolid(const PlaneFlags flags) {
if(flags & PlaneFlag::TextureCoordinates)
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolid,
Trade::meshAttributeDataNonOwningArray(AttributesSolid)};
{}, VerticesSolidTextureCoords,
Trade::meshAttributeDataNonOwningArray(AttributesSolidTextureCoords)};
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolidTextureCoords,
Trade::meshAttributeDataNonOwningArray(AttributesSolidTextureCoords)};
{}, VerticesSolid,
Trade::meshAttributeDataNonOwningArray(AttributesSolid)};
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData planeSolid(const PlaneTextureCoords textureCoords) {
return planeSolid(textureCoords == PlaneTextureCoords::Generate ?
PlaneFlag::TextureCoordinates : PlaneFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace {

43
src/Magnum/Primitives/Plane.h

@ -29,25 +29,52 @@
* @brief Function @ref Magnum::Primitives::planeSolid(), @ref Magnum::Primitives::planeWireframe()
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Trade/Trade.h"
#include "Magnum/Primitives/visibility.h"
namespace Magnum { namespace Primitives {
/**
@brief Whether to generate plane texture coordinates
@brief Plane flag
@m_since_latest
@see @ref PlaneFlags, @ref planeSolid()
*/
enum class PlaneFlag: UnsignedByte {
/** Generate texture coordinates with origin in bottom left corner */
TextureCoordinates = 1 << 0
};
/**
@brief Plane flags
@m_since_latest
@see @ref planeSolid()
*/
enum class PlaneTextureCoords: UnsignedByte {
typedef Containers::EnumSet<PlaneFlag> PlaneFlags;
CORRADE_ENUMSET_OPERATORS(PlaneFlags)
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Whether to generate plane texture coordinates
@m_deprecated_since_latest Use @ref PlaneFlags instead.
*/
enum class CORRADE_DEPRECATED_ENUM("use PlaneFlags instead") PlaneTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
/** Generate texture coordinates with origin in bottom left corner. */
Generate
};
#endif
/**
@brief Solid 3D plane
@param flags Flags
@m_since_latest
2x2 plane. Non-indexed @ref MeshPrimitive::TriangleStrip on the XY plane with
@ref VertexFormat::Vector3 positions and @ref VertexFormat::Vector3 normals in
@ -59,7 +86,17 @@ memory.
@see @ref planeWireframe(), @ref squareSolid(), @ref gradient3D(),
@ref MeshTools::generateTriangleStripIndices()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData planeSolid(PlaneTextureCoords textureCoords = PlaneTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData planeSolid(PlaneFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief planeSolid(PlaneFlags)
@m_deprecated_since_latest Use @ref planeSolid(PlaneFlags) instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use planeSolid(PlaneFlags) instead") Trade::MeshData planeSolid(PlaneTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 3D plane

21
src/Magnum/Primitives/Square.cpp

@ -70,16 +70,25 @@ constexpr Trade::MeshAttributeData AttributesSolidTextureCoords[]{
}
Trade::MeshData squareSolid(const SquareTextureCoords textureCoords) {
if(textureCoords != SquareTextureCoords::Generate)
Trade::MeshData squareSolid(const SquareFlags flags) {
if(flags & SquareFlag::TextureCoordinates)
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolid,
Trade::meshAttributeDataNonOwningArray(AttributesSolid)};
{}, VerticesSolidTextureCoords,
Trade::meshAttributeDataNonOwningArray(AttributesSolidTextureCoords)};
return Trade::MeshData{MeshPrimitive::TriangleStrip,
{}, VerticesSolidTextureCoords,
Trade::meshAttributeDataNonOwningArray(AttributesSolidTextureCoords)};
{}, VerticesSolid,
Trade::meshAttributeDataNonOwningArray(AttributesSolid)};
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData squareSolid(const SquareTextureCoords textureCoords) {
return squareSolid(textureCoords == SquareTextureCoords::Generate ?
SquareFlag::TextureCoordinates : SquareFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
namespace {

43
src/Magnum/Primitives/Square.h

@ -29,25 +29,52 @@
* @brief Function @ref Magnum::Primitives::squareSolid(), @ref Magnum::Primitives::squareWireframe()
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Primitives/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace Primitives {
/**
@brief Whether to generate square texture coordinates
@brief Square flag
@m_since_latest
@see @ref SquareFlags, @ref squareSolid()
*/
enum class SquareFlag: UnsignedByte {
/** Generate texture coordinates with origin in bottom left corner */
TextureCoordinates = 1 << 0
};
/**
@brief Square flags
@m_since_latest
@see @ref squareSolid()
*/
enum class SquareTextureCoords: UnsignedByte {
typedef Containers::EnumSet<SquareFlag> SquareFlags;
CORRADE_ENUMSET_OPERATORS(SquareFlags)
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Whether to generate square texture coordinates
@m_deprecated_since_latest Use @ref SquareFlags instead.
*/
enum class CORRADE_DEPRECATED_ENUM("use SquareFlags instead") SquareTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
/** Generate texture coordinates with origin in bottom left corner. */
Generate
};
#endif
/**
@brief Solid 2D square
@param flags Flags
@m_since_latest
2x2 square. Non-indexed @ref MeshPrimitive::TriangleStrip with interleaved
@ref VertexFormat::Vector2 positions and optional @ref VertexFormat::Vector2
@ -59,7 +86,17 @@ memory.
@see @ref squareWireframe(), @ref planeSolid(), @ref gradient2D(),
@ref MeshTools::generateTriangleStripIndices()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData squareSolid(SquareTextureCoords textureCoords = SquareTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData squareSolid(SquareFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief planeSolid(PlaneFlags)
@m_deprecated_since_latest Use @ref planeSolid(PlaneFlags) instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use squareSolid(SquareFlags) instead") Trade::MeshData squareSolid(SquareTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 2D square

2
src/Magnum/Primitives/Test/CapsuleTest.cpp

@ -185,7 +185,7 @@ void CapsuleTest::solid3DWithoutTextureCoords() {
}
void CapsuleTest::solid3DWithTextureCoords() {
Trade::MeshData capsule = capsule3DSolid(2, 2, 3, 0.5f, CapsuleTextureCoords::Generate);
Trade::MeshData capsule = capsule3DSolid(2, 2, 3, 0.5f, CapsuleFlag::TextureCoordinates);
CORRADE_COMPARE(capsule.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(capsule.isIndexed());

4
src/Magnum/Primitives/Test/CircleTest.cpp

@ -74,7 +74,7 @@ void CircleTest::solid2D() {
}
void CircleTest::solid2DTextureCoords() {
Trade::MeshData circle = Primitives::circle2DSolid(8, Primitives::CircleTextureCoords::Generate);
Trade::MeshData circle = Primitives::circle2DSolid(8, Primitives::Circle2DFlag::TextureCoordinates);
CORRADE_COMPARE(circle.primitive(), MeshPrimitive::TriangleFan);
CORRADE_VERIFY(!circle.isIndexed());
@ -126,7 +126,7 @@ void CircleTest::solid3D() {
}
void CircleTest::solid3DTextureCoords() {
Trade::MeshData circle = Primitives::circle3DSolid(8, Primitives::CircleTextureCoords::Generate);
Trade::MeshData circle = Primitives::circle3DSolid(8, Primitives::Circle3DFlag::TextureCoordinates);
CORRADE_COMPARE(circle.primitive(), MeshPrimitive::TriangleFan);
CORRADE_VERIFY(!circle.isIndexed());

4
src/Magnum/Primitives/Test/ConeTest.cpp

@ -150,7 +150,7 @@ void ConeTest::solidWithCaps() {
}
void ConeTest::solidWithTextureCoords() {
Trade::MeshData cone = coneSolid(2, 3, 1.0f, ConeFlag::GenerateTextureCoords);
Trade::MeshData cone = coneSolid(2, 3, 1.0f, ConeFlag::TextureCoordinates);
CORRADE_COMPARE(cone.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(cone.isIndexed());
@ -217,7 +217,7 @@ void ConeTest::solidWithTextureCoords() {
}
void ConeTest::solidWithTextureCoordsAndCaps() {
Trade::MeshData cone = coneSolid(2, 3, 1.0f, ConeFlag::GenerateTextureCoords|ConeFlag::CapEnd);
Trade::MeshData cone = coneSolid(2, 3, 1.0f, ConeFlag::TextureCoordinates|ConeFlag::CapEnd);
CORRADE_COMPARE(cone.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(cone.isIndexed());

4
src/Magnum/Primitives/Test/CylinderTest.cpp

@ -163,7 +163,7 @@ void CylinderTest::solidWithCaps() {
}
void CylinderTest::solidWithTextureCoords() {
Trade::MeshData cylinder = cylinderSolid(2, 3, 1.5f, CylinderFlag::GenerateTextureCoords);
Trade::MeshData cylinder = cylinderSolid(2, 3, 1.5f, CylinderFlag::TextureCoordinates);
CORRADE_COMPARE(cylinder.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(cylinder.isIndexed());
@ -230,7 +230,7 @@ void CylinderTest::solidWithTextureCoords() {
}
void CylinderTest::solidWithTextureCoordsAndCaps() {
Trade::MeshData cylinder = cylinderSolid(2, 3, 1.5f, CylinderFlag::GenerateTextureCoords|CylinderFlag::CapEnds);
Trade::MeshData cylinder = cylinderSolid(2, 3, 1.5f, CylinderFlag::TextureCoordinates|CylinderFlag::CapEnds);
CORRADE_COMPARE(cylinder.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(cylinder.isIndexed());

2
src/Magnum/Primitives/Test/GridTest.cpp

@ -127,7 +127,7 @@ void GridTest::solid3DWithoutAnything() {
}
void GridTest::solid3DWithNormalsAndTextureCoords() {
Trade::MeshData grid = grid3DSolid({5, 3}, GridFlag::GenerateNormals|GridFlag::GenerateTextureCoords);
Trade::MeshData grid = grid3DSolid({5, 3}, GridFlag::Normals|GridFlag::TextureCoordinates);
CORRADE_COMPARE(grid.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(grid.isIndexed());

2
src/Magnum/Primitives/Test/PlaneTest.cpp

@ -60,7 +60,7 @@ void PlaneTest::solid() {
}
void PlaneTest::solidTextured() {
Trade::MeshData plane = Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate);
Trade::MeshData plane = Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates);
CORRADE_COMPARE(plane.primitive(), MeshPrimitive::TriangleStrip);
CORRADE_VERIFY(!plane.isIndexed());

2
src/Magnum/Primitives/Test/SquareTest.cpp

@ -58,7 +58,7 @@ void SquareTest::solid() {
}
void SquareTest::solidTextured() {
Trade::MeshData square = Primitives::squareSolid(Primitives::SquareTextureCoords::Generate);
Trade::MeshData square = Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates);
CORRADE_COMPARE(square.primitive(), MeshPrimitive::TriangleStrip);
CORRADE_VERIFY(!square.isIndexed());

2
src/Magnum/Primitives/Test/UVSphereTest.cpp

@ -89,7 +89,7 @@ void UVSphereTest::solidWithoutTextureCoords() {
}
void UVSphereTest::solidWithTextureCoords() {
Trade::MeshData sphere = uvSphereSolid(3, 3, UVSphereTextureCoords::Generate);
Trade::MeshData sphere = uvSphereSolid(3, 3, UVSphereFlag::TextureCoordinates);
CORRADE_COMPARE(sphere.primitive(), MeshPrimitive::Triangles);
CORRADE_VERIFY(sphere.isIndexed());

14
src/Magnum/Primitives/UVSphere.cpp

@ -33,14 +33,12 @@
namespace Magnum { namespace Primitives {
Trade::MeshData uvSphereSolid(UnsignedInt rings, UnsignedInt segments, UVSphereTextureCoords textureCoords) {
Trade::MeshData uvSphereSolid(const UnsignedInt rings, const UnsignedInt segments, const UVSphereFlags flags) {
CORRADE_ASSERT(rings >= 2 && segments >= 3,
"Primitives::uvSphereSolid(): at least two rings and three segments expected",
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
Implementation::Spheroid sphere(segments, textureCoords == UVSphereTextureCoords::Generate ?
Implementation::Spheroid::TextureCoords::Generate :
Implementation::Spheroid::TextureCoords::DontGenerate);
Implementation::Spheroid sphere(segments, Implementation::Spheroid::Flag(UnsignedByte(flags)));
Float textureCoordsVIncrement = 1.0f/rings;
Rad ringAngleIncrement(Constants::pi()/rings);
@ -62,6 +60,14 @@ Trade::MeshData uvSphereSolid(UnsignedInt rings, UnsignedInt segments, UVSphereT
return sphere.finalize();
}
#ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_IGNORE_DEPRECATED_PUSH
Trade::MeshData uvSphereSolid(const UnsignedInt rings, const UnsignedInt segments, const UVSphereTextureCoords textureCoords) {
return uvSphereSolid(rings, segments, textureCoords == UVSphereTextureCoords::Generate ? UVSphereFlag::TextureCoordinates : UVSphereFlags{});
}
CORRADE_IGNORE_DEPRECATED_POP
#endif
Trade::MeshData uvSphereWireframe(const UnsignedInt rings, const UnsignedInt segments) {
CORRADE_ASSERT(rings >= 2 && rings%2 == 0 && segments >= 4 && segments%4 == 0,
"Primitives::uvSphereWireframe(): multiples of 2 rings and multiples of 4 segments expected",

48
src/Magnum/Primitives/UVSphere.h

@ -29,28 +29,42 @@
* @brief Class @ref Magnum::Primitives::uvSphereSolid(), @ref Magnum::Primitives::uvSphereWireframe()
*/
#include <Corrade/Containers/EnumSet.h>
#include <Corrade/Utility/Macros.h>
#include "Magnum/Trade/Trade.h"
#include "Magnum/Primitives/visibility.h"
namespace Magnum { namespace Primitives {
/**
@brief Whether to generate UV sphere texture coordinates
@brief UV sphere flag
@m_since_latest
@see @ref uvSphereSolid()
@see @ref UVSphereFlags, @ref uvSphereSolid()
*/
enum class UVSphereTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
Generate /**< Generate texture coordinates */
enum class UVSphereFlag: UnsignedByte {
TextureCoordinates = 1 << 0 /**< Generate texture coordinates */
};
/**
@brief UV sphere flags
@m_since_latest
@see @ref uvSphereSolid()
*/
typedef Containers::EnumSet<UVSphereFlag> UVSphereFlags;
CORRADE_ENUMSET_OPERATORS(UVSphereFlags)
/**
@brief Solid 3D UV sphere
@param rings Number of (face) rings. Must be larger or equal to
@cpp 2 @ce.
@param segments Number of (face) segments. Must be larger or
equal to @cpp 3 @ce.
@param textureCoords Whether to generate texture coordinates
@param flags Flags
@m_since_latest
Sphere with radius @cpp 1.0f @ce. @ref MeshPrimitive::Triangles with
@ref MeshIndexType::UnsignedInt indices, interleaved @ref VertexFormat::Vector3
@ -62,7 +76,27 @@ generated, vertices of one segment are duplicated for texture wrapping.
@see @ref icosphereSolid()
*/
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData uvSphereSolid(UnsignedInt rings, UnsignedInt segments, UVSphereTextureCoords textureCoords = UVSphereTextureCoords::DontGenerate);
MAGNUM_PRIMITIVES_EXPORT Trade::MeshData uvSphereSolid(UnsignedInt rings, UnsignedInt segments, UVSphereFlags flags = {});
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief Whether to generate UV sphere texture coordinates
@m_deprecated_since_latest Use @ref UVSphereFlags instead.
*/
enum class CORRADE_DEPRECATED("use UVSphereFlags instead") UVSphereTextureCoords: UnsignedByte {
DontGenerate, /**< Don't generate texture coordinates */
Generate /**< Generate texture coordinates */
};
/**
@brief @copybrief uvSphereSolid(UnsignedInt, UnsignedInt, UVSphereFlags)
@m_deprecated_since_latest Use @ref uvSphereSolid(UnsignedInt, UnsignedInt, UVSphereFlags)
instead.
*/
CORRADE_IGNORE_DEPRECATED_PUSH
MAGNUM_PRIMITIVES_EXPORT CORRADE_DEPRECATED("use uvSphereSolid() with UVSphereFlags instead") Trade::MeshData uvSphereSolid(UnsignedInt rings, UnsignedInt segments, UVSphereTextureCoords textureCoords);
CORRADE_IGNORE_DEPRECATED_POP
#endif
/**
@brief Wireframe 3D UV sphere

8
src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp

@ -267,7 +267,7 @@ void DistanceFieldVectorGLTest::renderDefaults2D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate));
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -323,7 +323,7 @@ void DistanceFieldVectorGLTest::renderDefaults3D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate));
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -382,7 +382,7 @@ void DistanceFieldVectorGLTest::render2D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate));
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -448,7 +448,7 @@ void DistanceFieldVectorGLTest::render3D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate));
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);

16
src/Magnum/Shaders/Test/FlatGLTest.cpp

@ -513,7 +513,7 @@ constexpr GL::TextureFormat TextureFormatRGBA =
void FlatGLTest::renderSinglePixelTextured2D() {
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate));
Primitives::Circle2DFlag::TextureCoordinates));
const Color4ub diffuseData[]{ 0x9999ff_rgb };
ImageView2D diffuseImage{PixelFormat::RGBA8Unorm, Vector2i{1}, diffuseData};
@ -551,7 +551,7 @@ void FlatGLTest::renderSinglePixelTextured2D() {
void FlatGLTest::renderSinglePixelTextured3D() {
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
const Color4ub diffuseData[]{ 0x9999ff_rgb };
ImageView2D diffuseImage{PixelFormat::RGBA8Unorm, Vector2i{1}, diffuseData};
@ -600,7 +600,7 @@ void FlatGLTest::renderTextured2D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate));
Primitives::Circle2DFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -656,7 +656,7 @@ void FlatGLTest::renderTextured3D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -715,7 +715,7 @@ template<class T> void FlatGLTest::renderVertexColor2D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
Trade::MeshData circleData = Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate);
Primitives::Circle2DFlag::TextureCoordinates);
/* Highlight a quarter */
Containers::Array<T> colorData{Containers::DirectInit, circleData.vertexCount(), 0x999999_rgbf};
@ -769,7 +769,7 @@ template<class T> void FlatGLTest::renderVertexColor3D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate);
Primitives::UVSphereFlag::TextureCoordinates);
/* Highlight the middle rings */
Containers::Array<T> colorData{Containers::DirectInit, sphereData.vertexCount(), 0x999999_rgbf};
@ -856,7 +856,7 @@ void FlatGLTest::renderAlpha2D() {
MAGNUM_VERIFY_NO_GL_ERROR();
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate));
Primitives::Circle2DFlag::TextureCoordinates));
Flat2D shader{data.flags};
shader.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
@ -907,7 +907,7 @@ void FlatGLTest::renderAlpha3D() {
MAGNUM_VERIFY_NO_GL_ERROR();
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
Flat3D shader{data.flags};
shader.setTransformationProjectionMatrix(

12
src/Magnum/Shaders/Test/PhongGLTest.cpp

@ -629,7 +629,7 @@ void PhongGLTest::renderSinglePixelTextured() {
setTestCaseDescription(data.name);
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
const Color4ub ambientData[]{ 0x330033_rgb };
ImageView2D ambientImage{PixelFormat::RGBA8Unorm, Vector2i{1}, ambientData};
@ -704,7 +704,7 @@ void PhongGLTest::renderTextured() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
Phong shader{data.flags, 2};
@ -815,7 +815,7 @@ void PhongGLTest::renderTexturedNormal() {
.setStorage(1, TextureFormatRGB, image->size())
.setSubImage(0, {}, *image);
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid( Primitives::PlaneTextureCoords::Generate));
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid( Primitives::PlaneFlag::TextureCoordinates));
/* Add hardcoded tangents */
/** @todo remove once MeshData is sane */
@ -887,7 +887,7 @@ template<class T> void PhongGLTest::renderVertexColor() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate);
Primitives::UVSphereFlag::TextureCoordinates);
/* Highlight the middle rings */
Containers::Array<T> colorData{Containers::DirectInit, sphereData.vertexCount(), 0x999999_rgbf};
@ -1079,7 +1079,7 @@ void PhongGLTest::renderAlpha() {
MAGNUM_VERIFY_NO_GL_ERROR();
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
Phong shader{data.flags, 2};
shader.setLightPositions({{-3.0f, -3.0f, 0.0f},
@ -1218,7 +1218,7 @@ void PhongGLTest::renderZeroLights() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate));
Primitives::UVSphereFlag::TextureCoordinates));
Phong shader{
Phong::Flag::AmbientTexture|Phong::Flag::AlphaMask

8
src/Magnum/Shaders/Test/VectorGLTest.cpp

@ -262,7 +262,7 @@ void VectorGLTest::renderDefaults2D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate));
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -309,7 +309,7 @@ void VectorGLTest::renderDefaults3D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate));
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -359,7 +359,7 @@ void VectorGLTest::render2D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate));
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
@ -421,7 +421,7 @@ void VectorGLTest::render3D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate));
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);

8
src/Magnum/Shaders/Test/VertexColorGLTest.cpp

@ -197,7 +197,7 @@ template<class T> void VertexColorGLTest::renderDefaults2D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
Trade::MeshData circleData = Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate);
Primitives::Circle2DFlag::TextureCoordinates);
/* All a single color */
Containers::Array<T> colorData{Containers::DirectInit, circleData.vertexCount(), 0xffffff_rgbf};
@ -238,7 +238,7 @@ template<class T> void VertexColorGLTest::renderDefaults3D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate);
Primitives::UVSphereFlag::TextureCoordinates);
/* All a single color */
Containers::Array<T> colorData{Containers::DirectInit, sphereData.vertexCount(), 0xffffff_rgbf};
@ -271,7 +271,7 @@ template<class T> void VertexColorGLTest::render2D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
Trade::MeshData circleData = Primitives::circle2DSolid(32,
Primitives::CircleTextureCoords::Generate);
Primitives::Circle2DFlag::TextureCoordinates);
/* Highlight a quarter */
Containers::Array<T> colorData{Containers::DirectInit, circleData.vertexCount(), 0x9999ff_rgbf};
@ -316,7 +316,7 @@ template<class T> void VertexColorGLTest::render3D() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereTextureCoords::Generate);
Primitives::UVSphereFlag::TextureCoordinates);
/* Highlight the middle rings */
Containers::Array<T> colorData{Containers::DirectInit, sphereData.vertexCount(), 0x9999ff_rgbf};

Loading…
Cancel
Save