Browse Source

Trade: make MeshAttributeData constexpr.

This makes it possible to have fully allocation-less MeshData, with
statically defined indices and attributes. Only the final MeshData
construction needs to be done at runtime because Array is not constexpr,
but that isn't anything heavy anyway.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
c74b4c6b90
  1. 27
      src/Magnum/Trade/MeshData.cpp
  2. 30
      src/Magnum/Trade/MeshData.h
  3. 13
      src/Magnum/Trade/Test/MeshDataTest.cpp

27
src/Magnum/Trade/MeshData.cpp

@ -40,23 +40,13 @@ MeshIndexData::MeshIndexData(const MeshIndexType type, const Containers::ArrayVi
"Trade::MeshIndexData: view size" << data.size() << "does not correspond to" << type, );
}
MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const char>& data) noexcept: name{name}, format{format}, data{data} {
MeshAttributeData::MeshAttributeData(const MeshAttribute name, const VertexFormat format, const Containers::StridedArrayView1D<const void>& data) noexcept: MeshAttributeData{name, format, data, nullptr} {
/* Yes, this calls into a constexpr function defined in the header --
because I feel that makes more sense than duplicating the full assert
logic */
/** @todo support zero / negative stride? would be hard to transfer to GL */
CORRADE_ASSERT(data.empty() || std::ptrdiff_t(vertexFormatSize(format)) <= data.stride(),
"Trade::MeshAttributeData: view stride" << data.stride() << "is not large enough to contain" << format, );
CORRADE_ASSERT(
(name == MeshAttribute::Position &&
(format == VertexFormat::Vector2 ||
format == VertexFormat::Vector3)) ||
(name == MeshAttribute::Normal &&
(format == VertexFormat::Vector3)) ||
(name == MeshAttribute::Color &&
(format == VertexFormat::Vector3 ||
format == VertexFormat::Vector4)) ||
(name == MeshAttribute::TextureCoordinates &&
(format == VertexFormat::Vector2)) ||
isMeshAttributeCustom(name) /* can be any format */,
"Trade::MeshAttributeData:" << format << "is not a valid format for" << name, );
}
Containers::Array<MeshAttributeData> meshAttributeDataNonOwningArray(const Containers::ArrayView<const MeshAttributeData> view) {
@ -88,10 +78,11 @@ MeshData::MeshData(const MeshPrimitive primitive, Containers::Array<char>&& inde
constructors */
for(std::size_t i = 0; i != _attributes.size(); ++i) {
const MeshAttributeData& attribute = _attributes[i];
CORRADE_ASSERT(attribute.data.size() == _vertexCount,
"Trade::MeshData: attribute" << i << "has" << attribute.data.size() << "vertices but" << _vertexCount << "expected", );
CORRADE_ASSERT(attribute.data.empty() || (&attribute.data.front() >= _vertexData.begin() && &attribute.data.back() + vertexFormatSize(attribute.format) <= _vertexData.end()),
"Trade::MeshData: attribute" << i << "[" << Debug::nospace << static_cast<const void*>(&attribute.data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(&attribute.data.back() + vertexFormatSize(attribute.format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_vertexData.end()) << Debug::nospace << "]", );
const Containers::StridedArrayView1D<const char> data = Containers::arrayCast<const char>(attribute.data);
CORRADE_ASSERT(data.size() == _vertexCount,
"Trade::MeshData: attribute" << i << "has" << data.size() << "vertices but" << _vertexCount << "expected", );
CORRADE_ASSERT(data.empty() || (&data.front() >= _vertexData.begin() && &data.back() + vertexFormatSize(attribute.format) <= _vertexData.end()),
"Trade::MeshData: attribute" << i << "[" << Debug::nospace << static_cast<const void*>(&data.front()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(&data.back() + vertexFormatSize(attribute.format)) << Debug::nospace << "] is not contained in passed vertexData array [" << Debug::nospace << static_cast<const void*>(_vertexData.begin()) << Debug::nospace << ":" << Debug::nospace << static_cast<const void*>(_vertexData.end()) << Debug::nospace << "]", );
}
#endif
}

30
src/Magnum/Trade/MeshData.h

@ -216,7 +216,7 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
* initialization of the attribute array for @ref MeshData, expected to
* be replaced with concrete values later.
*/
explicit MeshAttributeData() noexcept: name{}, format{}, data{} {}
constexpr explicit MeshAttributeData() noexcept: name{}, format{}, data{} {}
/**
* @brief Type-erased constructor
@ -227,7 +227,7 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
* Expects that @p data stride is large enough to fit @p type and that
* @p type corresponds to @p name.
*/
explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const char>& data) noexcept;
explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const void>& data) noexcept;
/**
* @brief Constructor
@ -237,18 +237,20 @@ class MAGNUM_TRADE_EXPORT MeshAttributeData {
* Detects @ref VertexFormat based on @p T and calls
* @ref MeshAttributeData(MeshAttribute, VertexFormat, const Containers::StridedArrayView1D<const void>&).
*/
template<class T> explicit MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept;
template<class T> constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept;
/** @overload */
template<class T> explicit MeshAttributeData(MeshAttribute name, const Containers::ArrayView<T>& data) noexcept: MeshAttributeData{name, Containers::stridedArrayView(data)} {}
template<class T> constexpr explicit MeshAttributeData(MeshAttribute name, const Containers::ArrayView<T>& data) noexcept: MeshAttributeData{name, Containers::stridedArrayView(data)} {}
private:
constexpr explicit MeshAttributeData(MeshAttribute name, VertexFormat format, const Containers::StridedArrayView1D<const void>& data, std::nullptr_t) noexcept;
/* Not prefixed with _ because we use them like public in MeshData */
friend MeshData;
MeshAttribute name;
/* Here's some room for flags */
VertexFormat format;
Containers::StridedArrayView1D<const char> data;
Containers::StridedArrayView1D<const void> data;
};
/** @relatesalso MeshAttributeData
@ -1027,7 +1029,23 @@ namespace Implementation {
constexpr MeshIndexData::MeshIndexData(MeshIndexType type, Containers::ArrayView<const void> data, std::nullptr_t):
type{type}, data{(CORRADE_CONSTEXPR_ASSERT(!data.empty(), "Trade::MeshIndexData: index array can't be empty, create a non-indexed mesh instead"), data)} {}
template<class T> MeshAttributeData::MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept: MeshAttributeData{name, Implementation::vertexFormatFor<typename std::remove_const<T>::type>(), Containers::arrayCast<const char>(data)} {}
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 == MeshAttribute::Position &&
(format == VertexFormat::Vector2 ||
format == VertexFormat::Vector3)) ||
(name == MeshAttribute::Normal &&
(format == VertexFormat::Vector3)) ||
(name == MeshAttribute::Color &&
(format == VertexFormat::Vector3 ||
format == VertexFormat::Vector4)) ||
(name == MeshAttribute::TextureCoordinates &&
(format == VertexFormat::Vector2)) ||
isMeshAttributeCustom(name) /* can be any format */,
"Trade::MeshAttributeData:" << format << "is not a valid format for" << name), data)}
{}
template<class T> constexpr MeshAttributeData::MeshAttributeData(MeshAttribute name, const Containers::StridedArrayView1D<T>& data) noexcept: MeshAttributeData{name, Implementation::vertexFormatFor<typename std::remove_const<T>::type>(), data, nullptr} {}
template<class T> Containers::ArrayView<const T> MeshData::indices() const {
CORRADE_ASSERT(isIndexed(),

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

@ -330,6 +330,12 @@ void MeshDataTest::constructIndexTypeErasedWrongSize() {
CORRADE_COMPARE(out.str(), "Trade::MeshIndexData: view size 6 does not correspond to MeshIndexType::UnsignedInt\n");
}
constexpr Vector2 Positions[] {
{1.2f, 0.2f},
{2.2f, 1.1f},
{-0.2f, 7.2f}
};
void MeshDataTest::constructAttribute() {
Containers::Array<char> positionData{3*sizeof(Vector2)};
auto positionView = Containers::arrayCast<Vector2>(positionData);
@ -340,6 +346,13 @@ void MeshDataTest::constructAttribute() {
CORRADE_COMPARE(data.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(static_cast<const void*>(data.attribute<Vector2>(0).data()),
positionView.data());
constexpr MeshAttributeData cpositions{MeshAttribute::Position, Containers::arrayView(Positions)};
MeshData cdata{MeshPrimitive::Points, {}, Positions, {cpositions}};
CORRADE_COMPARE(cdata.attributeName(0), MeshAttribute::Position);
CORRADE_COMPARE(cdata.attributeFormat(0), VertexFormat::Vector2);
CORRADE_COMPARE(static_cast<const void*>(cdata.attribute<Vector2>(0).data()),
Positions);
}
void MeshDataTest::constructAttributeCustom() {

Loading…
Cancel
Save