Browse Source

Trade: support packed attributes in MeshData.

This was a LONG unexpected detour... I mean, I expected it, but not so
soon.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
ed88b35ec8
  1. 165
      src/Magnum/Trade/MeshData.cpp
  2. 193
      src/Magnum/Trade/MeshData.h
  3. 366
      src/Magnum/Trade/Test/MeshDataTest.cpp

165
src/Magnum/Trade/MeshData.cpp

@ -28,6 +28,7 @@
#include <Corrade/Utility/Algorithms.h> #include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
#include "Magnum/Math/PackingBatch.h"
#include "Magnum/Trade/Implementation/arrayUtilities.h" #include "Magnum/Trade/Implementation/arrayUtilities.h"
namespace Magnum { namespace Trade { namespace Magnum { namespace Trade {
@ -365,10 +366,39 @@ void MeshData::positions2DInto(const Containers::StridedArrayView1D<Vector2> des
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
const auto destination2f = Containers::arrayCast<2, Float>(destination);
/* Copy 2D positions as-is, for 3D positions ignore Z */ /* Copy 2D positions as-is, for 3D positions ignore Z */
if(attribute._format == VertexFormat::Vector2 || if(attribute._format == VertexFormat::Vector2 ||
attribute._format == VertexFormat::Vector3) attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination); Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination);
else if(attribute._format == VertexFormat::Vector2h ||
attribute._format == VertexFormat::Vector3h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ub ||
attribute._format == VertexFormat::Vector3ub)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2b ||
attribute._format == VertexFormat::Vector3b)
Math::castInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2us ||
attribute._format == VertexFormat::Vector3us)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2s ||
attribute._format == VertexFormat::Vector3s)
Math::castInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ubNormalized ||
attribute._format == VertexFormat::Vector3ubNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2bNormalized ||
attribute._format == VertexFormat::Vector3bNormalized)
Math::unpackInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2usNormalized ||
attribute._format == VertexFormat::Vector3usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2sNormalized ||
attribute._format == VertexFormat::Vector3sNormalized)
Math::unpackInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
@ -384,19 +414,71 @@ void MeshData::positions3DInto(const Containers::StridedArrayView1D<Vector3> des
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions3DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::positions3DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
/* For 2D positions copy the XY part to the first two components and then const Containers::StridedArrayView2D<Float> destination2f = Containers::arrayCast<2, Float>(Containers::arrayCast<Vector2>(destination));
fill the Z with a single value */ const Containers::StridedArrayView2D<Float> destination3f = Containers::arrayCast<2, Float>(destination);
if(attribute._format == VertexFormat::Vector2) {
/* For 2D positions copy the XY part to the first two components */
if(attribute._format == VertexFormat::Vector2)
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), Utility::copy(Containers::arrayCast<const Vector2>(attribute._data),
Containers::arrayCast<Vector2>(destination)); Containers::arrayCast<Vector2>(destination));
else if(attribute._format == VertexFormat::Vector2h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ub)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2b)
Math::castInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2us)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2s)
Math::castInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ubNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2bNormalized)
Math::unpackInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2sNormalized)
Math::unpackInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
/* Copy 3D positions as-is */
else if(attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination);
else if(attribute._format == VertexFormat::Vector3h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3ub)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3b)
Math::castInto(Containers::arrayCast<2, const Byte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3us)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3s)
Math::castInto(Containers::arrayCast<2, const Short>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3ubNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3bNormalized)
Math::unpackInto(Containers::arrayCast<2, const Byte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3sNormalized)
Math::unpackInto(Containers::arrayCast<2, const Short>(attribute._data, 3), destination3f);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
/* For 2D positions finally fill the Z with a single value */
if(attribute._format == VertexFormat::Vector2 ||
attribute._format == VertexFormat::Vector2h ||
attribute._format == VertexFormat::Vector2ub ||
attribute._format == VertexFormat::Vector2b ||
attribute._format == VertexFormat::Vector2us ||
attribute._format == VertexFormat::Vector2s ||
attribute._format == VertexFormat::Vector2ubNormalized ||
attribute._format == VertexFormat::Vector2bNormalized ||
attribute._format == VertexFormat::Vector2usNormalized ||
attribute._format == VertexFormat::Vector2sNormalized) {
constexpr Float z[1]{0.0f}; constexpr Float z[1]{0.0f};
Utility::copy( Utility::copy(
Containers::stridedArrayView(z).broadcasted<0>(_vertexCount), Containers::stridedArrayView(z).broadcasted<0>(_vertexCount),
Containers::arrayCast<2, Float>(destination).transposed<0, 1>()[2]); destination3f.transposed<0, 1>()[2]);
/* Copy 3D positions as-is */ }
} else if(attribute._format == VertexFormat::Vector3) {
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination);
} else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
Containers::Array<Vector3> MeshData::positions3DAsArray(const UnsignedInt id) const { Containers::Array<Vector3> MeshData::positions3DAsArray(const UnsignedInt id) const {
@ -411,8 +493,16 @@ void MeshData::normalsInto(const Containers::StridedArrayView1D<Vector3> destina
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::normalsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
const auto destination3f = Containers::arrayCast<2, Float>(destination);
if(attribute._format == VertexFormat::Vector3) if(attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination); Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), destination);
else if(attribute._format == VertexFormat::Vector3h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3bNormalized)
Math::unpackInto(Containers::arrayCast<2, const Byte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3sNormalized)
Math::unpackInto(Containers::arrayCast<2, const Short>(attribute._data, 3), destination3f);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
@ -428,8 +518,28 @@ void MeshData::textureCoordinates2DInto(const Containers::StridedArrayView1D<Vec
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::textureCoordinates2DInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
const auto destination2f = Containers::arrayCast<2, Float>(destination);
if(attribute._format == VertexFormat::Vector2) if(attribute._format == VertexFormat::Vector2)
Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination); Utility::copy(Containers::arrayCast<const Vector2>(attribute._data), destination);
else if(attribute._format == VertexFormat::Vector2h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ub)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2b)
Math::castInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2us)
Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2s)
Math::castInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2ubNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2bNormalized)
Math::unpackInto(Containers::arrayCast<2, const Byte>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 2), destination2f);
else if(attribute._format == VertexFormat::Vector2sNormalized)
Math::unpackInto(Containers::arrayCast<2, const Short>(attribute._data, 2), destination2f);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
} }
@ -445,20 +555,43 @@ void MeshData::colorsInto(const Containers::StridedArrayView1D<Color4> destinati
CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::colorsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), ); CORRADE_ASSERT(destination.size() == _vertexCount, "Trade::MeshData::colorsInto(): expected a view with" << _vertexCount << "elements but got" << destination.size(), );
const MeshAttributeData& attribute = _attributes[attributeId]; const MeshAttributeData& attribute = _attributes[attributeId];
const Containers::StridedArrayView2D<Float> destination3f = Containers::arrayCast<2, Float>(Containers::arrayCast<Vector3>(destination));
const Containers::StridedArrayView2D<Float> destination4f = Containers::arrayCast<2, Float>(destination);
/* For three-component colors copy the RGB part to the first three /* For three-component colors copy the RGB part to the first three
components and then fill the alpha with a single value */ components */
if(attribute._format == VertexFormat::Vector3) { if(attribute._format == VertexFormat::Vector3)
Utility::copy(Containers::arrayCast<const Vector3>(attribute._data), Utility::copy(Containers::arrayCast<const Vector3>(attribute._data),
Containers::arrayCast<Vector3>(destination)); Containers::arrayCast<Vector3>(destination));
constexpr Float alpha[1]{1.0f}; else if(attribute._format == VertexFormat::Vector3h)
Utility::copy( Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
Containers::stridedArrayView(alpha).broadcasted<0>(_vertexCount), else if(attribute._format == VertexFormat::Vector3ubNormalized)
Containers::arrayCast<2, Float>(destination).transposed<0, 1>()[3]); Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 3), destination3f);
else if(attribute._format == VertexFormat::Vector3usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 3), destination3f);
/* Copy four-component colors as-is */ /* Copy four-component colors as-is */
} else if(attribute._format == VertexFormat::Vector4) { else if(attribute._format == VertexFormat::Vector4)
Utility::copy(Containers::arrayCast<const Vector4>(attribute._data), Utility::copy(Containers::arrayCast<const Vector4>(attribute._data),
Containers::arrayCast<Vector4>(destination)); Containers::arrayCast<Vector4>(destination));
} else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ else if(attribute._format == VertexFormat::Vector4h)
Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 4), destination4f);
else if(attribute._format == VertexFormat::Vector4ubNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attribute._data, 4), destination4f);
else if(attribute._format == VertexFormat::Vector4usNormalized)
Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attribute._data, 4), destination4f);
else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
/* For three-component colors finally fill the alpha with a single value */
if(attribute._format == VertexFormat::Vector3 ||
attribute._format == VertexFormat::Vector3h ||
attribute._format == VertexFormat::Vector3ubNormalized ||
attribute._format == VertexFormat::Vector3usNormalized) {
constexpr Float alpha[1]{1.0f};
Utility::copy(
Containers::stridedArrayView(alpha).broadcasted<0>(_vertexCount),
destination4f.transposed<0, 1>()[3]);
}
} }
Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const { Containers::Array<Color4> MeshData::colorsAsArray(const UnsignedInt id) const {

193
src/Magnum/Trade/MeshData.h

@ -55,37 +55,54 @@ enum class MeshAttribute: UnsignedShort {
AbstractImporter::meshAttributeForName()) */ AbstractImporter::meshAttributeForName()) */
/** /**
* Position. Type is usually @ref Magnum::Vector2 "Vector2" for 2D and * Position. Type is usually @ref VertexFormat::Vector2 for 2D and
* @ref Magnum::Vector3 "Vector3" for 3D. Corresponds to * @ref VertexFormat::Vector3 for 3D, but can be also any of
* @ref Shaders::Generic::Position. * @ref VertexFormat::Vector2h, @ref VertexFormat::Vector3h,
* @see @ref VertexFormat::Vector2, @ref VertexFormat::Vector3, * @ref VertexFormat::Vector2ub, @ref VertexFormat::Vector2ubNormalized,
* @ref MeshData::positions2DAsArray(), * @ref VertexFormat::Vector2b, @ref VertexFormat::Vector2bNormalized,
* @ref VertexFormat::Vector2us, @ref VertexFormat::Vector2usNormalized,
* @ref VertexFormat::Vector2s, @ref VertexFormat::Vector2sNormalized,
* @ref VertexFormat::Vector3ub, @ref VertexFormat::Vector3ubNormalized,
* @ref VertexFormat::Vector3b, @ref VertexFormat::Vector3bNormalized,
* @ref VertexFormat::Vector3us, @ref VertexFormat::Vector3usNormalized,
* @ref VertexFormat::Vector3s or @ref VertexFormat::Vector3sNormalized.
* Corresponds to @ref Shaders::Generic::Position.
* @see @ref MeshData::positions2DAsArray(),
* @ref MeshData::positions3DAsArray() * @ref MeshData::positions3DAsArray()
*/ */
Position = 1, Position = 1,
/** /**
* Normal. Type is usually @ref Magnum::Vector3 "Vector3". Corresponds to * Normal. Type is usually @ref VertexFormat::Vector3, but can be also
* @ref VertexFormat::Vector3h. @ref VertexFormat::Vector3bNormalized or
* @ref VertexFormat::Vector3sNormalized. Corresponds to
* @ref Shaders::Generic::Normal. * @ref Shaders::Generic::Normal.
* @see @ref VertexFormat::Vector3, @ref MeshData::normalsAsArray() * @see @ref MeshData::normalsAsArray()
*/ */
Normal, Normal,
/** /**
* Texture coordinates. Type is usually @ref Magnum::Vector2 "Vector2" for * Texture coordinates. Type is usually @ref VertexFormat::Vector2 for
* 2D coordinates. Corresponds to @ref Shaders::Generic::TextureCoordinates. * 2D coordinates, but can be also any of @ref VertexFormat::Vector2h,
* @see @ref VertexFormat::Vector2, * @ref VertexFormat::Vector2ub, @ref VertexFormat::Vector2ubNormalized,
* @ref MeshData::textureCoordinates2DAsArray() * @ref VertexFormat::Vector2b, @ref VertexFormat::Vector2bNormalized,
* @ref VertexFormat::Vector2us, @ref VertexFormat::Vector2usNormalized,
* @ref VertexFormat::Vector2s or @ref VertexFormat::Vector2sNormalized.
* Corresponds to @ref Shaders::Generic::TextureCoordinates.
* @see @ref MeshData::textureCoordinates2DAsArray()
*/ */
TextureCoordinates, TextureCoordinates,
/** /**
* Vertex color. Type is usually @ref Magnum::Vector3 "Vector3" or * Vertex color. Type is usually @ref VertexFormat::Vector3 or
* @ref Magnum::Vector4 "Vector4" (or @ref Color3 / @ref Color4). * @ref VertexFormat::Vector4, but can be also any of
* Corresponds to @ref Shaders::Generic::Color3 or * @ref VertexFormat::Vector3h, @ref VertexFormat::Vector4h,
* @ref Shaders::Generic::Color4. * @ref VertexFormat::Vector3ubNormalized,
* @see @ref VertexFormat::Vector3, @ref VertexFormat::Vector4, * @ref VertexFormat::Vector3usNormalized,
* @ref MeshData::colorsAsArray() * @ref VertexFormat::Vector4ubNormalized or
* @ref VertexFormat::Vector4usNormalized. Corresponds to
* @ref Shaders::Generic::Color3 or @ref Shaders::Generic::Color4.
* @see @ref MeshData::colorsAsArray()
*/ */
Color, Color,
@ -261,6 +278,27 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
* *
* Detects @ref VertexFormat based on @p T and calls * Detects @ref VertexFormat based on @p T and calls
* @ref MeshAttributeData(MeshAttribute, VertexFormat, const Containers::StridedArrayView1D<const void>&). * @ref MeshAttributeData(MeshAttribute, VertexFormat, const Containers::StridedArrayView1D<const void>&).
* For most types known by Magnum, the detected @ref VertexFormat is of
* the same name as the type (so e.g. @ref Magnum::Vector3ui "Vector3ui"
* gets recognized as @ref VertexFormat::Vector3ui), with the
* following exceptions:
*
* - @ref Color3ub is recognized as
* @ref VertexFormat::Vector3ubNormalized
* - @ref Color3us is recognized as
* @ref VertexFormat::Vector3usNormalized
* - @ref Color4ub is recognized as
* @ref VertexFormat::Vector4ubNormalized
* - @ref Color4us is recognized as
* @ref VertexFormat::Vector4usNormalized
*
* This also means that if you have a @ref Magnum::Vector2s "Vector2s",
* for example, and want to pick a
* @ref VertexFormat::Vector2sNormalized instead of the
* (autodetected) @ref VertexFormat::Vector2s, you need to specify
* it explicitly --- there's no way the library can infer this from the
* type alone, except for the color types above (which are generally
* always normalized).
*/ */
template<class T> constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept; template<class T> constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept;
@ -1164,6 +1202,7 @@ namespace Implementation {
template<> constexpr MeshIndexType meshIndexTypeFor<UnsignedShort>() { return MeshIndexType::UnsignedShort; } template<> constexpr MeshIndexType meshIndexTypeFor<UnsignedShort>() { return MeshIndexType::UnsignedShort; }
template<> constexpr MeshIndexType meshIndexTypeFor<UnsignedInt>() { return MeshIndexType::UnsignedInt; } template<> constexpr MeshIndexType meshIndexTypeFor<UnsignedInt>() { return MeshIndexType::UnsignedInt; }
/* Implicit mapping from a format to enum (1:1) */
template<class T> constexpr VertexFormat vertexFormatFor() { template<class T> constexpr VertexFormat vertexFormatFor() {
/* C++ why there isn't an obvious way to do such a thing?! */ /* C++ why there isn't an obvious way to do such a thing?! */
static_assert(sizeof(T) == 0, "unsupported attribute type"); static_assert(sizeof(T) == 0, "unsupported attribute type");
@ -1173,6 +1212,8 @@ namespace Implementation {
#define _c(format) \ #define _c(format) \
template<> constexpr VertexFormat vertexFormatFor<format>() { return VertexFormat::format; } template<> constexpr VertexFormat vertexFormatFor<format>() { return VertexFormat::format; }
_c(Float) _c(Float)
_c(Half)
_c(Double)
_c(UnsignedByte) _c(UnsignedByte)
_c(Byte) _c(Byte)
_c(UnsignedShort) _c(UnsignedShort)
@ -1180,28 +1221,128 @@ namespace Implementation {
_c(UnsignedInt) _c(UnsignedInt)
_c(Int) _c(Int)
_c(Vector2) _c(Vector2)
_c(Vector2h)
_c(Vector2d)
_c(Vector2ub)
_c(Vector2b)
_c(Vector2us)
_c(Vector2s)
_c(Vector2ui)
_c(Vector2i)
_c(Vector3) _c(Vector3)
_c(Vector3h)
_c(Vector3d)
_c(Vector3ub)
_c(Vector3b)
_c(Vector3us)
_c(Vector3s)
_c(Vector3ui)
_c(Vector3i)
_c(Vector4) _c(Vector4)
_c(Vector4h)
_c(Vector4d)
_c(Vector4ub)
_c(Vector4b)
_c(Vector4us)
_c(Vector4s)
_c(Vector4ui)
_c(Vector4i)
#undef _c #undef _c
#endif #endif
template<> constexpr VertexFormat vertexFormatFor<Color3>() { return VertexFormat::Vector3; } template<> constexpr VertexFormat vertexFormatFor<Color3>() { return VertexFormat::Vector3; }
template<> constexpr VertexFormat vertexFormatFor<Color3h>() { return VertexFormat::Vector3h; }
template<> constexpr VertexFormat vertexFormatFor<Color3ub>() { return VertexFormat::Vector3ubNormalized; }
template<> constexpr VertexFormat vertexFormatFor<Color3us>() { return VertexFormat::Vector3usNormalized; }
template<> constexpr VertexFormat vertexFormatFor<Color4>() { return VertexFormat::Vector4; } template<> constexpr VertexFormat vertexFormatFor<Color4>() { return VertexFormat::Vector4; }
template<> constexpr VertexFormat vertexFormatFor<Color4h>() { return VertexFormat::Vector4h; }
template<> constexpr VertexFormat vertexFormatFor<Color4ub>() { return VertexFormat::Vector4ubNormalized; }
template<> constexpr VertexFormat vertexFormatFor<Color4us>() { return VertexFormat::Vector4usNormalized; }
/* Check if enum is compatible with a format (1:n). Mostly just 1:1 mapping
tho, so reusing vertexFormatFor(), with a few exceptions. */
template<class T> constexpr bool isVertexFormatCompatible(VertexFormat type) {
return vertexFormatFor<T>() == type;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
#define _c(format_) \
template<> constexpr bool isVertexFormatCompatible<format_>(VertexFormat format) { \
return format == VertexFormat::format_ || \
format == VertexFormat::format_ ## Normalized; \
}
_c(UnsignedByte)
_c(Byte)
_c(UnsignedShort)
_c(Short)
_c(Vector2ub)
_c(Vector2b)
_c(Vector2us)
_c(Vector2s)
_c(Vector3ub)
_c(Vector3b)
_c(Vector3us)
_c(Vector3s)
_c(Vector4ub)
_c(Vector4b)
_c(Vector4us)
_c(Vector4s)
/* For Color[34]u[sb] we expect the format to be normalized, which is
handled by vertexFormatFor() properly already */
#undef _c
#endif
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
#endif #endif
constexpr MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, std::nullptr_t) noexcept: constexpr MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data, std::nullptr_t) noexcept:
_name{name}, _format{format}, _data{(CORRADE_CONSTEXPR_ASSERT( _name{name}, _format{format}, _data{(CORRADE_CONSTEXPR_ASSERT(
/* Double formats intentionally not supported for any builtin attributes
right now -- only for custom formats */
(name == MeshAttribute::Position && (name == MeshAttribute::Position &&
(format == VertexFormat::Vector2 || (format == VertexFormat::Vector2 ||
format == VertexFormat::Vector3)) || format == VertexFormat::Vector2h ||
format == VertexFormat::Vector2ub ||
format == VertexFormat::Vector2ubNormalized ||
format == VertexFormat::Vector2b ||
format == VertexFormat::Vector2bNormalized ||
format == VertexFormat::Vector2us ||
format == VertexFormat::Vector2usNormalized ||
format == VertexFormat::Vector2s ||
format == VertexFormat::Vector2sNormalized ||
format == VertexFormat::Vector3 ||
format == VertexFormat::Vector3h ||
format == VertexFormat::Vector3ub ||
format == VertexFormat::Vector3ubNormalized ||
format == VertexFormat::Vector3b ||
format == VertexFormat::Vector3bNormalized ||
format == VertexFormat::Vector3us ||
format == VertexFormat::Vector3usNormalized ||
format == VertexFormat::Vector3s ||
format == VertexFormat::Vector3sNormalized)) ||
(name == MeshAttribute::Normal && (name == MeshAttribute::Normal &&
(format == VertexFormat::Vector3)) || (format == VertexFormat::Vector3 ||
format == VertexFormat::Vector3h ||
format == VertexFormat::Vector3bNormalized ||
format == VertexFormat::Vector3sNormalized)) ||
(name == MeshAttribute::Color && (name == MeshAttribute::Color &&
(format == VertexFormat::Vector3 || (format == VertexFormat::Vector3 ||
format == VertexFormat::Vector4)) || format == VertexFormat::Vector3h ||
format == VertexFormat::Vector3ubNormalized ||
format == VertexFormat::Vector3usNormalized ||
format == VertexFormat::Vector4 ||
format == VertexFormat::Vector4h ||
format == VertexFormat::Vector4ubNormalized ||
format == VertexFormat::Vector4usNormalized)) ||
(name == MeshAttribute::TextureCoordinates && (name == MeshAttribute::TextureCoordinates &&
(format == VertexFormat::Vector2)) || (format == VertexFormat::Vector2 ||
format == VertexFormat::Vector2h ||
format == VertexFormat::Vector2ub ||
format == VertexFormat::Vector2ubNormalized ||
format == VertexFormat::Vector2b ||
format == VertexFormat::Vector2bNormalized ||
format == VertexFormat::Vector2us ||
format == VertexFormat::Vector2usNormalized ||
format == VertexFormat::Vector2s ||
format == VertexFormat::Vector2sNormalized)) ||
isMeshAttributeCustom(name) /* can be any format */, isMeshAttributeCustom(name) /* can be any format */,
"Trade::MeshAttributeData:" << format << "is not a valid format for" << name), data)} "Trade::MeshAttributeData:" << format << "is not a valid format for" << name), data)}
{} {}
@ -1233,7 +1374,7 @@ template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(Un
#ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {}; if(!data.stride()[1]) return {};
#endif #endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id]._format, CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[id]._format),
"Trade::MeshData::attribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr); "Trade::MeshData::attribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr);
return Containers::arrayCast<1, const T>(data); return Containers::arrayCast<1, const T>(data);
} }
@ -1243,7 +1384,7 @@ template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(U
#ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */ #ifdef CORRADE_GRACEFUL_ASSERT /* Sigh. Brittle. Better idea? */
if(!data.stride()[1]) return {}; if(!data.stride()[1]) return {};
#endif #endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[id]._format, CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[id]._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr); "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[id]._name << "of format" << _attributes[id]._format, nullptr);
return Containers::arrayCast<1, T>(data); return Containers::arrayCast<1, T>(data);
} }
@ -1256,7 +1397,7 @@ template<class T> Containers::StridedArrayView1D<const T> MeshData::attribute(Me
#ifndef CORRADE_NO_ASSERT #ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id); const UnsignedInt attributeId = attributeFor(name, id);
#endif #endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[attributeId]._format, CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[attributeId]._format),
"Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr); "Trade::MeshData::attribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr);
return Containers::arrayCast<1, const T>(data); return Containers::arrayCast<1, const T>(data);
} }
@ -1269,8 +1410,8 @@ template<class T> Containers::StridedArrayView1D<T> MeshData::mutableAttribute(M
#ifndef CORRADE_NO_ASSERT #ifndef CORRADE_NO_ASSERT
const UnsignedInt attributeId = attributeFor(name, id); const UnsignedInt attributeId = attributeFor(name, id);
#endif #endif
CORRADE_ASSERT(Implementation::vertexFormatFor<T>() == _attributes[attributeId]._format, CORRADE_ASSERT(Implementation::isVertexFormatCompatible<T>(_attributes[attributeId]._format),
"Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId]._name << "of type" << _attributes[attributeId]._format, nullptr); "Trade::MeshData::mutableAttribute(): improper type requested for" << _attributes[attributeId]._name << "of format" << _attributes[attributeId]._format, nullptr);
return Containers::arrayCast<1, T>(data); return Containers::arrayCast<1, T>(data);
} }

366
src/Magnum/Trade/Test/MeshDataTest.cpp

@ -29,6 +29,7 @@
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
#include "Magnum/Math/Half.h"
#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace Trade { namespace Test { namespace { namespace Magnum { namespace Trade { namespace Test { namespace {
@ -96,14 +97,28 @@ struct MeshDataTest: TestSuite::Tester {
template<class T> void indicesAsArray(); template<class T> void indicesAsArray();
void indicesIntoArrayInvalidSize(); void indicesIntoArrayInvalidSize();
template<class T> void positions2DAsArray(); template<class T> void positions2DAsArray();
template<class T> void positions2DAsArrayPackedUnsigned();
template<class T> void positions2DAsArrayPackedSigned();
template<class T> void positions2DAsArrayPackedUnsignedNormalized();
template<class T> void positions2DAsArrayPackedSignedNormalized();
void positions2DIntoArrayInvalidSize(); void positions2DIntoArrayInvalidSize();
template<class T> void positions3DAsArray(); template<class T> void positions3DAsArray();
template<class T> void positions3DAsArrayPackedUnsigned();
template<class T> void positions3DAsArrayPackedSigned();
template<class T> void positions3DAsArrayPackedUnsignedNormalized();
template<class T> void positions3DAsArrayPackedSignedNormalized();
void positions3DIntoArrayInvalidSize(); void positions3DIntoArrayInvalidSize();
template<class T> void normalsAsArray(); template<class T> void normalsAsArray();
template<class T> void normalsAsArrayPackedSignedNormalized();
void normalsIntoArrayInvalidSize(); void normalsIntoArrayInvalidSize();
template<class T> void textureCoordinates2DAsArray(); template<class T> void textureCoordinates2DAsArray();
template<class T> void textureCoordinates2DAsArrayPackedUnsigned();
template<class T> void textureCoordinates2DAsArrayPackedSigned();
template<class T> void textureCoordinates2DAsArrayPackedUnsignedNormalized();
template<class T> void textureCoordinates2DAsArrayPackedSignedNormalized();
void textureCoordinates2DIntoArrayInvalidSize(); void textureCoordinates2DIntoArrayInvalidSize();
template<class T> void colorsAsArray(); template<class T> void colorsAsArray();
template<class T> void colorsAsArrayPackedUnsignedNormalized();
void colorsIntoArrayInvalidSize(); void colorsIntoArrayInvalidSize();
void mutableAccessNotAllowed(); void mutableAccessNotAllowed();
@ -202,17 +217,71 @@ MeshDataTest::MeshDataTest() {
&MeshDataTest::indicesAsArray<UnsignedInt>, &MeshDataTest::indicesAsArray<UnsignedInt>,
&MeshDataTest::indicesIntoArrayInvalidSize, &MeshDataTest::indicesIntoArrayInvalidSize,
&MeshDataTest::positions2DAsArray<Vector2>, &MeshDataTest::positions2DAsArray<Vector2>,
&MeshDataTest::positions2DAsArray<Vector2h>,
&MeshDataTest::positions2DAsArray<Vector3>, &MeshDataTest::positions2DAsArray<Vector3>,
&MeshDataTest::positions2DAsArray<Vector3h>,
&MeshDataTest::positions2DAsArrayPackedUnsigned<Vector2ub>,
&MeshDataTest::positions2DAsArrayPackedUnsigned<Vector2us>,
&MeshDataTest::positions2DAsArrayPackedUnsigned<Vector3ub>,
&MeshDataTest::positions2DAsArrayPackedUnsigned<Vector3us>,
&MeshDataTest::positions2DAsArrayPackedSigned<Vector2b>,
&MeshDataTest::positions2DAsArrayPackedSigned<Vector2s>,
&MeshDataTest::positions2DAsArrayPackedSigned<Vector3b>,
&MeshDataTest::positions2DAsArrayPackedSigned<Vector3s>,
&MeshDataTest::positions2DAsArrayPackedUnsignedNormalized<Vector2ub>,
&MeshDataTest::positions2DAsArrayPackedUnsignedNormalized<Vector2us>,
&MeshDataTest::positions2DAsArrayPackedUnsignedNormalized<Vector3ub>,
&MeshDataTest::positions2DAsArrayPackedUnsignedNormalized<Vector3us>,
&MeshDataTest::positions2DAsArrayPackedSignedNormalized<Vector2b>,
&MeshDataTest::positions2DAsArrayPackedSignedNormalized<Vector2s>,
&MeshDataTest::positions2DAsArrayPackedSignedNormalized<Vector3b>,
&MeshDataTest::positions2DAsArrayPackedSignedNormalized<Vector3s>,
&MeshDataTest::positions2DIntoArrayInvalidSize, &MeshDataTest::positions2DIntoArrayInvalidSize,
&MeshDataTest::positions3DAsArray<Vector2>, &MeshDataTest::positions3DAsArray<Vector2>,
&MeshDataTest::positions3DAsArray<Vector2h>,
&MeshDataTest::positions3DAsArray<Vector3>, &MeshDataTest::positions3DAsArray<Vector3>,
&MeshDataTest::positions3DAsArray<Vector3h>,
&MeshDataTest::positions3DAsArrayPackedUnsigned<Vector2ub>,
&MeshDataTest::positions3DAsArrayPackedUnsigned<Vector2us>,
&MeshDataTest::positions3DAsArrayPackedUnsigned<Vector3ub>,
&MeshDataTest::positions3DAsArrayPackedUnsigned<Vector3us>,
&MeshDataTest::positions3DAsArrayPackedSigned<Vector2b>,
&MeshDataTest::positions3DAsArrayPackedSigned<Vector2s>,
&MeshDataTest::positions3DAsArrayPackedSigned<Vector3b>,
&MeshDataTest::positions3DAsArrayPackedSigned<Vector3s>,
&MeshDataTest::positions3DAsArrayPackedUnsignedNormalized<Vector2ub>,
&MeshDataTest::positions3DAsArrayPackedUnsignedNormalized<Vector2us>,
&MeshDataTest::positions3DAsArrayPackedUnsignedNormalized<Vector3ub>,
&MeshDataTest::positions3DAsArrayPackedUnsignedNormalized<Vector3us>,
&MeshDataTest::positions3DAsArrayPackedSignedNormalized<Vector2b>,
&MeshDataTest::positions3DAsArrayPackedSignedNormalized<Vector2s>,
&MeshDataTest::positions3DAsArrayPackedSignedNormalized<Vector3b>,
&MeshDataTest::positions3DAsArrayPackedSignedNormalized<Vector3s>,
&MeshDataTest::positions3DIntoArrayInvalidSize, &MeshDataTest::positions3DIntoArrayInvalidSize,
&MeshDataTest::normalsAsArray<Vector3>, &MeshDataTest::normalsAsArray<Vector3>,
&MeshDataTest::normalsAsArray<Vector3h>,
&MeshDataTest::normalsAsArrayPackedSignedNormalized<Vector3b>,
&MeshDataTest::normalsAsArrayPackedSignedNormalized<Vector3s>,
&MeshDataTest::normalsIntoArrayInvalidSize, &MeshDataTest::normalsIntoArrayInvalidSize,
&MeshDataTest::textureCoordinates2DAsArray<Vector2>, &MeshDataTest::textureCoordinates2DAsArray<Vector2>,
&MeshDataTest::textureCoordinates2DAsArray<Vector2h>,
&MeshDataTest::textureCoordinates2DAsArrayPackedUnsigned<Vector2ub>,
&MeshDataTest::textureCoordinates2DAsArrayPackedUnsigned<Vector2us>,
&MeshDataTest::textureCoordinates2DAsArrayPackedSigned<Vector2b>,
&MeshDataTest::textureCoordinates2DAsArrayPackedSigned<Vector2s>,
&MeshDataTest::textureCoordinates2DAsArrayPackedUnsignedNormalized<Vector2ub>,
&MeshDataTest::textureCoordinates2DAsArrayPackedUnsignedNormalized<Vector2us>,
&MeshDataTest::textureCoordinates2DAsArrayPackedSignedNormalized<Vector2b>,
&MeshDataTest::textureCoordinates2DAsArrayPackedSignedNormalized<Vector2s>,
&MeshDataTest::textureCoordinates2DIntoArrayInvalidSize, &MeshDataTest::textureCoordinates2DIntoArrayInvalidSize,
&MeshDataTest::colorsAsArray<Color3>, &MeshDataTest::colorsAsArray<Color3>,
&MeshDataTest::colorsAsArray<Color3h>,
&MeshDataTest::colorsAsArray<Color4>, &MeshDataTest::colorsAsArray<Color4>,
&MeshDataTest::colorsAsArray<Color4h>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color3ub>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color3us>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4ub>,
&MeshDataTest::colorsAsArrayPackedUnsignedNormalized<Color4us>,
&MeshDataTest::colorsIntoArrayInvalidSize, &MeshDataTest::colorsIntoArrayInvalidSize,
&MeshDataTest::mutableAccessNotAllowed, &MeshDataTest::mutableAccessNotAllowed,
@ -1290,9 +1359,25 @@ template<class> struct NameTraits;
static const char* name() { return #format; } \ static const char* name() { return #format; } \
}; };
_c(Vector2) _c(Vector2)
_c(Vector2h)
_c(Vector2ub)
_c(Vector2b)
_c(Vector2us)
_c(Vector2s)
_c(Vector3) _c(Vector3)
_c(Vector3h)
_c(Vector3ub)
_c(Vector3b)
_c(Vector3us)
_c(Vector3s)
_c(Color3) _c(Color3)
_c(Color3h)
_c(Color3ub)
_c(Color3us)
_c(Color4) _c(Color4)
_c(Color4h)
_c(Color4ub)
_c(Color4us)
#undef _c #undef _c
template<class T> void MeshDataTest::indicesAsArray() { template<class T> void MeshDataTest::indicesAsArray() {
@ -1324,12 +1409,13 @@ void MeshDataTest::indicesIntoArrayInvalidSize() {
template<class T> void MeshDataTest::positions2DAsArray() { template<class T> void MeshDataTest::positions2DAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName(NameTraits<T>::name());
typedef typename T::Type U;
Containers::Array<char> vertexData{3*sizeof(T)}; Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData); auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Vector2{2.0f, 1.0f}); positionsView[0] = T::pad(Math::Vector2<U>{U(2.0f), U(1.0f)});
positionsView[1] = T::pad(Vector2{0.0f, -1.0f}); positionsView[1] = T::pad(Math::Vector2<U>{U(0.0f), U(-1.0f)});
positionsView[2] = T::pad(Vector2{-2.0f, 3.0f}); positionsView[2] = T::pad(Math::Vector2<U>{U(-2.0f), U(3.0f)});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions2DAsArray(), CORRADE_COMPARE_AS(data.positions2DAsArray(),
@ -1337,6 +1423,70 @@ template<class T> void MeshDataTest::positions2DAsArray() {
TestSuite::Compare::Container); TestSuite::Compare::Container);
} }
template<class T> void MeshDataTest::positions2DAsArrayPackedUnsigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector2<typename T::Type>{2, 1});
positionsView[1] = T::pad(Math::Vector2<typename T::Type>{0, 15});
positionsView[2] = T::pad(Math::Vector2<typename T::Type>{22, 3});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions2DAsArray(),
Containers::arrayView<Vector2>({{2.0f, 1.0f}, {0.0f, 15.0f}, {22.0f, 3.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions2DAsArrayPackedSigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector2<typename T::Type>{2, 1});
positionsView[1] = T::pad(Math::Vector2<typename T::Type>{0, -15});
positionsView[2] = T::pad(Math::Vector2<typename T::Type>{-22, 3});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions2DAsArray(),
Containers::arrayView<Vector2>({{2.0f, 1.0f}, {0.0f, -15.0f}, {-22.0f, 3.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions2DAsArrayPackedUnsignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector2<typename T::Type>{Math::pack<typename T::Type>(1.0f), 0});
positionsView[1] = T::pad(Math::Vector2<typename T::Type>{0, Math::pack<typename T::Type>(1.0f)});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
positionsView}}};
CORRADE_COMPARE_AS(data.positions2DAsArray(),
Containers::arrayView<Vector2>({{1.0f, 0.0f}, {0.0f, 1.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions2DAsArrayPackedSignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector2<typename T::Type>{Math::pack<typename T::Type>(1.0f), 0});
positionsView[1] = T::pad(Math::Vector2<typename T::Type>{0, Math::pack<typename T::Type>(-1.0f)});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
positionsView}}};
CORRADE_COMPARE_AS(data.positions2DAsArray(),
Containers::arrayView<Vector2>({{1.0f, 0.0f}, {0.0f, -1.0f}}),
TestSuite::Compare::Container);
}
void MeshDataTest::positions2DIntoArrayInvalidSize() { void MeshDataTest::positions2DIntoArrayInvalidSize() {
Containers::Array<char> vertexData{3*sizeof(Vector2)}; Containers::Array<char> vertexData{3*sizeof(Vector2)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData)}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, Containers::arrayCast<Vector2>(vertexData)}}};
@ -1351,18 +1501,91 @@ void MeshDataTest::positions2DIntoArrayInvalidSize() {
template<class T> void MeshDataTest::positions3DAsArray() { template<class T> void MeshDataTest::positions3DAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName(NameTraits<T>::name());
typedef typename T::Type U;
Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
/* Needs to be sufficiently representable to have the test work also for
half floats */
positionsView[0] = T::pad(Math::Vector3<U>{U(2.0f), U(1.0f), U(0.75f)});
positionsView[1] = T::pad(Math::Vector3<U>{U(0.0f), U(-1.0f), U(1.25f)});
positionsView[2] = T::pad(Math::Vector3<U>{U(-2.0f), U(3.0f), U(2.5f)});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{2.0f, 1.0f, 0.75f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{0.0f, -1.0f, 1.25f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{-2.0f, 3.0f, 2.5f}))
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions3DAsArrayPackedUnsigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)}; Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData); auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Vector3{2.0f, 1.0f, 0.3f}); positionsView[0] = T::pad(Math::Vector3<typename T::Type>{2, 1, 135});
positionsView[1] = T::pad(Vector3{0.0f, -1.0f, 1.1f}); positionsView[1] = T::pad(Math::Vector3<typename T::Type>{0, 15, 2});
positionsView[2] = T::pad(Vector3{-2.0f, 3.0f, 2.2f}); positionsView[2] = T::pad(Math::Vector3<typename T::Type>{22, 3, 192});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({ CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({
Vector3::pad(T::pad(Vector3{2.0f, 1.0f, 0.3f})), Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{2.0f, 1.0f, 135.0f})),
Vector3::pad(T::pad(Vector3{0.0f, -1.0f, 1.1f})), Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{0.0f, 15.0f, 2.0f})),
Vector3::pad(T::pad(Vector3{-2.0f, 3.0f, 2.2f})) Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{22.0f, 3.0f, 192.0f}))
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions3DAsArrayPackedSigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector3<typename T::Type>{2, 1, -117});
positionsView[1] = T::pad(Math::Vector3<typename T::Type>{0, -15, 2});
positionsView[2] = T::pad(Math::Vector3<typename T::Type>{-22, 3, 86});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position, positionsView}}};
CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{2.0f, 1.0f, -117.0f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{0.0f, -15.0f, 2.0f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{-22.0f, 3.0f, 86.0f}))
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions3DAsArrayPackedUnsignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector3<typename T::Type>{Math::pack<typename T::Type>(1.0f), 0, Math::pack<typename T::Type>(1.0f)});
positionsView[1] = T::pad(Math::Vector3<typename T::Type>{0, Math::pack<typename T::Type>(1.0f), 0});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
positionsView}}};
CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{1.0f, 0.0f, 1.0f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{0.0f, 1.0f, 0.0f}))
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::positions3DAsArrayPackedSignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto positionsView = Containers::arrayCast<T>(vertexData);
positionsView[0] = T::pad(Math::Vector3<typename T::Type>{Math::pack<typename T::Type>(1.0f), 0, Math::pack<typename T::Type>(1.0f)});
positionsView[1] = T::pad(Math::Vector3<typename T::Type>{0, Math::pack<typename T::Type>(-1.0f), 0});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Position,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
positionsView}}};
CORRADE_COMPARE_AS(data.positions3DAsArray(), Containers::arrayView<Vector3>({
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{1.0f, 0.0f, 1.0f})),
Vector3::pad(Math::Vector<T::Size, Float>::pad(Vector3{0.0f, -1.0f, 0.0f}))
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }
@ -1380,16 +1603,36 @@ void MeshDataTest::positions3DIntoArrayInvalidSize() {
template<class T> void MeshDataTest::normalsAsArray() { template<class T> void MeshDataTest::normalsAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName(NameTraits<T>::name());
typedef typename T::Type U;
Containers::Array<char> vertexData{3*sizeof(T)}; Containers::Array<char> vertexData{3*sizeof(T)};
auto normalsView = Containers::arrayCast<T>(vertexData); auto normalsView = Containers::arrayCast<T>(vertexData);
normalsView[0] = {2.0f, 1.0f, 0.3f}; /* Needs to be sufficiently representable to have the test work also for
normalsView[1] = {0.0f, -1.0f, 1.1f}; half floats */
normalsView[2] = {-2.0f, 3.0f, 2.2f}; normalsView[0] = {U(2.0f), U(1.0f), U(0.75f)};
normalsView[1] = {U(0.0f), U(-1.0f), U(1.25f)};
normalsView[2] = {U(-2.0f), U(3.0f), U(2.5f)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Normal, normalsView}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Normal, normalsView}}};
CORRADE_COMPARE_AS(data.normalsAsArray(), Containers::arrayView<Vector3>({ CORRADE_COMPARE_AS(data.normalsAsArray(), Containers::arrayView<Vector3>({
{2.0f, 1.0f, 0.3f}, {0.0f, -1.0f, 1.1f}, {-2.0f, 3.0f, 2.2f}, {2.0f, 1.0f, 0.75f}, {0.0f, -1.0f, 1.25f}, {-2.0f, 3.0f, 2.5f},
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::normalsAsArrayPackedSignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto normalsView = Containers::arrayCast<T>(vertexData);
normalsView[0] = {Math::pack<typename T::Type>(1.0f), 0, Math::pack<typename T::Type>(1.0f)};
normalsView[1] = {0, Math::pack<typename T::Type>(-1.0f), 0};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Normal,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
normalsView}}};
CORRADE_COMPARE_AS(data.normalsAsArray(), Containers::arrayView<Vector3>({
{1.0f, 0.0f, 1.0f}, {0.0f, -1.0f, 0.0f}
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }
@ -1407,12 +1650,13 @@ void MeshDataTest::normalsIntoArrayInvalidSize() {
template<class T> void MeshDataTest::textureCoordinates2DAsArray() { template<class T> void MeshDataTest::textureCoordinates2DAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName(NameTraits<T>::name());
typedef typename T::Type U;
Containers::Array<char> vertexData{3*sizeof(T)}; Containers::Array<char> vertexData{3*sizeof(T)};
auto textureCoordinatesView = Containers::arrayCast<T>(vertexData); auto textureCoordinatesView = Containers::arrayCast<T>(vertexData);
textureCoordinatesView[0] = {2.0f, 1.0f}; textureCoordinatesView[0] = {U(2.0f), U(1.0f)};
textureCoordinatesView[1] = {0.0f, -1.0f}; textureCoordinatesView[1] = {U(0.0f), U(-1.0f)};
textureCoordinatesView[2] = {-2.0f, 3.0f}; textureCoordinatesView[2] = {U(-2.0f), U(3.0f)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, textureCoordinatesView}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, textureCoordinatesView}}};
CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(), Containers::arrayView<Vector2>({ CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(), Containers::arrayView<Vector2>({
@ -1420,6 +1664,70 @@ template<class T> void MeshDataTest::textureCoordinates2DAsArray() {
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }
template<class T> void MeshDataTest::textureCoordinates2DAsArrayPackedUnsigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto textureCoordinatesView = Containers::arrayCast<T>(vertexData);
textureCoordinatesView[0] = {2, 1};
textureCoordinatesView[1] = {0, 15};
textureCoordinatesView[2] = {22, 3};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, textureCoordinatesView}}};
CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(),
Containers::arrayView<Vector2>({{2.0f, 1.0f}, {0.0f, 15.0f}, {22.0f, 3.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::textureCoordinates2DAsArrayPackedSigned() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{3*sizeof(T)};
auto textureCoordinatesView = Containers::arrayCast<T>(vertexData);
textureCoordinatesView[0] = {2, 1};
textureCoordinatesView[1] = {0, -15};
textureCoordinatesView[2] = {-22, 3};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, textureCoordinatesView}}};
CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(),
Containers::arrayView<Vector2>({{2.0f, 1.0f}, {0.0f, -15.0f}, {-22.0f, 3.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::textureCoordinates2DAsArrayPackedUnsignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto textureCoordinatesView = Containers::arrayCast<T>(vertexData);
textureCoordinatesView[0] = {Math::pack<typename T::Type>(1.0f), 0};
textureCoordinatesView[1] = {0, Math::pack<typename T::Type>(1.0f)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
textureCoordinatesView}}};
CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(),
Containers::arrayView<Vector2>({{1.0f, 0.0f}, {0.0f, 1.0f}}),
TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::textureCoordinates2DAsArrayPackedSignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto textureCoordinatesView = Containers::arrayCast<T>(vertexData);
textureCoordinatesView[0] = {Math::pack<typename T::Type>(1.0f), 0};
textureCoordinatesView[1] = {0, Math::pack<typename T::Type>(-1.0f)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates,
/* Assuming the normalized enum is always after the non-normalized */
VertexFormat(UnsignedInt(Implementation::vertexFormatFor<T>()) + 1),
textureCoordinatesView}}};
CORRADE_COMPARE_AS(data.textureCoordinates2DAsArray(),
Containers::arrayView<Vector2>({{1.0f, 0.0f}, {0.0f, -1.0f}}),
TestSuite::Compare::Container);
}
void MeshDataTest::textureCoordinates2DIntoArrayInvalidSize() { void MeshDataTest::textureCoordinates2DIntoArrayInvalidSize() {
Containers::Array<char> vertexData{3*sizeof(Vector2)}; Containers::Array<char> vertexData{3*sizeof(Vector2)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, Containers::arrayCast<Vector2>(vertexData)}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::TextureCoordinates, Containers::arrayCast<Vector2>(vertexData)}}};
@ -1434,16 +1742,34 @@ void MeshDataTest::textureCoordinates2DIntoArrayInvalidSize() {
template<class T> void MeshDataTest::colorsAsArray() { template<class T> void MeshDataTest::colorsAsArray() {
setTestCaseTemplateName(NameTraits<T>::name()); setTestCaseTemplateName(NameTraits<T>::name());
typedef typename T::Type U;
Containers::Array<char> vertexData{3*sizeof(T)}; Containers::Array<char> vertexData{3*sizeof(T)};
auto colorsView = Containers::arrayCast<T>(vertexData); auto colorsView = Containers::arrayCast<T>(vertexData);
colorsView[0] = 0xff3366_rgbf; /* Can't use e.g. 0xff3366_rgbf because that's not representable in
colorsView[1] = 0x99aacc_rgbf; half-floats */
colorsView[2] = 0x3377ff_rgbf; colorsView[0] = {U(2.0f), U(1.0f), U(0.75f)};
colorsView[1] = {U(0.0f), U(-1.0f), U(1.25f)};
colorsView[2] = {U(-2.0f), U(3.0f), U(2.5f)};
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Color, colorsView}}};
CORRADE_COMPARE_AS(data.colorsAsArray(), Containers::arrayView<Color4>({
{2.0f, 1.0f, 0.75f}, {0.0f, -1.0f, 1.25f}, {-2.0f, 3.0f, 2.5f},
}), TestSuite::Compare::Container);
}
template<class T> void MeshDataTest::colorsAsArrayPackedUnsignedNormalized() {
setTestCaseTemplateName(NameTraits<T>::name());
Containers::Array<char> vertexData{2*sizeof(T)};
auto colorsView = Containers::arrayCast<T>(vertexData);
colorsView[0] = T::pad(Math::Color4<typename T::Type>{Math::pack<typename T::Type>(1.0f), 0, Math::pack<typename T::Type>(1.0f), 0});
colorsView[1] = T::pad(Math::Color4<typename T::Type>{0, Math::pack<typename T::Type>(1.0f), 0, Math::pack<typename T::Type>(1.0f)});
MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Color, colorsView}}}; MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Color, colorsView}}};
CORRADE_COMPARE_AS(data.colorsAsArray(), Containers::arrayView<Color4>({ CORRADE_COMPARE_AS(data.colorsAsArray(), Containers::arrayView<Color4>({
0xff3366_rgbf, 0x99aacc_rgbf, 0x3377ff_rgbf Color4::pad(Math::Vector<T::Size, Float>::pad(Vector4{1.0f, 0.0f, 1.0f, 0.0f}), 1.0f),
Color4::pad(Math::Vector<T::Size, Float>::pad(Vector4{0.0f, 1.0f, 0.0f, 1.0f}), 1.0f)
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }

Loading…
Cancel
Save