Browse Source

MeshTools: unify naming of MeshData arguments.

pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
d06ac097c1
  1. 40
      src/Magnum/MeshTools/Combine.cpp
  2. 8
      src/Magnum/MeshTools/Combine.h
  3. 54
      src/Magnum/MeshTools/Compile.cpp
  4. 18
      src/Magnum/MeshTools/Compile.h
  5. 48
      src/Magnum/MeshTools/CompressIndices.cpp
  6. 4
      src/Magnum/MeshTools/CompressIndices.h
  7. 30
      src/Magnum/MeshTools/Duplicate.cpp
  8. 12
      src/Magnum/MeshTools/Duplicate.h
  9. 148
      src/Magnum/MeshTools/FilterAttributes.cpp
  10. 30
      src/Magnum/MeshTools/FilterAttributes.h
  11. 66
      src/Magnum/MeshTools/GenerateIndices.cpp
  12. 4
      src/Magnum/MeshTools/GenerateIndices.h
  13. 162
      src/Magnum/MeshTools/Interleave.cpp
  14. 46
      src/Magnum/MeshTools/Interleave.h
  15. 90
      src/Magnum/MeshTools/Reference.cpp
  16. 14
      src/Magnum/MeshTools/Reference.h
  17. 20
      src/Magnum/MeshTools/RemoveDuplicates.cpp
  18. 4
      src/Magnum/MeshTools/RemoveDuplicates.h
  19. 196
      src/Magnum/MeshTools/Transform.cpp
  20. 18
      src/Magnum/MeshTools/Transform.h

40
src/Magnum/MeshTools/Combine.cpp

@ -43,20 +43,20 @@ Trade::MeshData combineIndexedImplementation(
#ifndef CORRADE_NO_ASSERT
const char* assertPrefix,
#endif
const MeshPrimitive primitive, Containers::Array<char>& combinedIndices, const UnsignedInt indexCount, const UnsignedInt indexStride, const Containers::Iterable<const Trade::MeshData>& data)
const MeshPrimitive primitive, Containers::Array<char>& combinedIndices, const UnsignedInt indexCount, const UnsignedInt indexStride, const Containers::Iterable<const Trade::MeshData>& meshes)
{
/* Calculate attribute count and vertex stride */
UnsignedInt attributeCount = 0;
UnsignedInt vertexStride = 0;
for(std::size_t i = 0; i != data.size(); ++i) {
attributeCount += data[i].attributeCount();
for(UnsignedInt j = 0; j != data[i].attributeCount(); ++j) {
const VertexFormat format = data[i].attributeFormat(j);
for(std::size_t i = 0; i != meshes.size(); ++i) {
attributeCount += meshes[i].attributeCount();
for(UnsignedInt j = 0; j != meshes[i].attributeCount(); ++j) {
const VertexFormat format = meshes[i].attributeFormat(j);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format),
assertPrefix << "attribute" << j << "of mesh" << i << "has an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(format)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
vertexStride += vertexFormatSize(format)*Math::max(data[i].attributeArraySize(j), UnsignedShort{1});
vertexStride += vertexFormatSize(format)*Math::max(meshes[i].attributeArraySize(j), UnsignedShort{1});
}
}
@ -75,7 +75,7 @@ Trade::MeshData combineIndexedImplementation(
std::size_t indexOffset = 0;
std::size_t attributeOffset = 0;
std::size_t vertexOffset = 0;
for(const Trade::MeshData& mesh: data) {
for(const Trade::MeshData& mesh: meshes) {
const UnsignedInt indexSize = mesh.isIndexed() ?
meshIndexTypeSize(mesh.indexType()) : 4;
Containers::StridedArrayView2D<const char> indices{combinedIndices,
@ -110,8 +110,8 @@ Trade::MeshData combineIndexedImplementation(
}
Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade::MeshData>& data) {
CORRADE_ASSERT(!data.isEmpty(),
Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade::MeshData>& meshes) {
CORRADE_ASSERT(!meshes.isEmpty(),
"MeshTools::combineIndexedAttributes(): no meshes passed",
(Trade::MeshData{MeshPrimitive{}, 0}));
@ -122,22 +122,22 @@ Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade:
MeshPrimitive primitive{};
UnsignedInt indexCount{};
UnsignedInt indexStride = 0;
for(std::size_t i = 0; i != data.size(); ++i) {
CORRADE_ASSERT(data[i].isIndexed(),
for(std::size_t i = 0; i != meshes.size(); ++i) {
CORRADE_ASSERT(meshes[i].isIndexed(),
"MeshTools::combineIndexedAttributes(): data" << i << "is not indexed",
(Trade::MeshData{MeshPrimitive{}, 0}));
const MeshIndexType indexType = data[i].indexType();
const MeshIndexType indexType = meshes[i].indexType();
CORRADE_ASSERT(!isMeshIndexTypeImplementationSpecific(indexType),
"MeshTools::combineIndexedAttributes(): data" << i << "has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(indexType)),
(Trade::MeshData{MeshPrimitive{}, 0}));
if(i == 0) {
primitive = data[i].primitive();
indexCount = data[i].indexCount();
primitive = meshes[i].primitive();
indexCount = meshes[i].indexCount();
} else {
CORRADE_ASSERT(data[i].primitive() == primitive,
"MeshTools::combineIndexedAttributes(): data" << i << "is" << data[i].primitive() << "but expected" << primitive, (Trade::MeshData{MeshPrimitive{}, 0}));
CORRADE_ASSERT(data[i].indexCount() == indexCount,
"MeshTools::combineIndexedAttributes(): data" << i << "has" << data[i].indexCount() << "indices but expected" << indexCount, (Trade::MeshData{MeshPrimitive{}, 0}));
CORRADE_ASSERT(meshes[i].primitive() == primitive,
"MeshTools::combineIndexedAttributes(): data" << i << "is" << meshes[i].primitive() << "but expected" << primitive, (Trade::MeshData{MeshPrimitive{}, 0}));
CORRADE_ASSERT(meshes[i].indexCount() == indexCount,
"MeshTools::combineIndexedAttributes(): data" << i << "has" << meshes[i].indexCount() << "indices but expected" << indexCount, (Trade::MeshData{MeshPrimitive{}, 0}));
}
indexStride += meshIndexTypeSize(indexType);
}
@ -149,7 +149,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade:
Containers::Array<char> combinedIndices{NoInit, indexCount*indexStride};
{
std::size_t indexOffset = 0;
for(const Trade::MeshData& mesh: data) {
for(const Trade::MeshData& mesh: meshes) {
const UnsignedInt indexSize = meshIndexTypeSize(mesh.indexType());
Containers::StridedArrayView2D<char> dst{combinedIndices,
combinedIndices.data() + indexOffset,
@ -167,7 +167,7 @@ Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade:
#ifndef CORRADE_NO_ASSERT
"MeshTools::combineIndexedAttributes():",
#endif
primitive, combinedIndices, indexCount, indexStride, data);
primitive, combinedIndices, indexCount, indexStride, meshes);
}
Trade::MeshData combineFaceAttributes(const Trade::MeshData& mesh, const Trade::MeshData& faceAttributes) {

8
src/Magnum/MeshTools/Combine.h

@ -48,8 +48,8 @@ namespace Magnum { namespace MeshTools {
@brief Combine differently indexed attributes into a single mesh
@m_since{2020,06}
Assuming each @p data contains only unique vertex data, creates an indexed mesh
that contains all attributes from @p data combined, with duplicate vertices
Assuming all @p meshes contain only unique vertex data, creates an indexed mesh
that contains all attributes from @p meshes combined, with duplicate vertices
removed. For example, when you have a position and a normal array, each indexed
with separate indices like this:
@ -85,7 +85,7 @@ Vertex data unreferenced by the index buffers are discarded. This means the
function can be also called with just a single argument to compact a mesh with
a sparse index buffer.
Expects that @p data is non-empty and all data have the same primitive and
Expects that @p meshes is non-empty and all data have the same primitive and
index count. All inputs have to be indexed. For non-indexed attributes
combining can be done much more efficiently using @ref duplicate(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>),
alternatively you can turn a non-indexed attribute to an indexed one first
@ -95,7 +95,7 @@ implementation-specific format.
@see @ref isMeshIndexTypeImplementationSpecific(),
@ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade::MeshData>& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData combineIndexedAttributes(const Containers::Iterable<const Trade::MeshData>& meshes);
/**
@brief Combine per-face attributes into an existing mesh

54
src/Magnum/MeshTools/Compile.cpp

@ -252,61 +252,61 @@ GL::Mesh compileInternal(const Trade::MeshData& meshData, const CompileFlags fla
}
GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer&& indices, GL::Buffer&& vertices) {
return compileInternal(meshData, std::move(indices), std::move(vertices), {});
GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer&& indices, GL::Buffer&& vertices) {
return compileInternal(mesh, std::move(indices), std::move(vertices), {});
}
GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer& indices, GL::Buffer& vertices) {
return compileInternal(meshData, GL::Buffer::wrap(indices.id(), GL::Buffer::TargetHint::ElementArray), GL::Buffer::wrap(vertices.id(), GL::Buffer::TargetHint::Array), CompileFlag::NoWarnOnCustomAttributes);
GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer& indices, GL::Buffer& vertices) {
return compileInternal(mesh, GL::Buffer::wrap(indices.id(), GL::Buffer::TargetHint::ElementArray), GL::Buffer::wrap(vertices.id(), GL::Buffer::TargetHint::Array), CompileFlag::NoWarnOnCustomAttributes);
}
GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer& indices, GL::Buffer&& vertices) {
return compileInternal(meshData, GL::Buffer::wrap(indices.id(), GL::Buffer::TargetHint::ElementArray), std::move(vertices), CompileFlag::NoWarnOnCustomAttributes);
GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer& indices, GL::Buffer&& vertices) {
return compileInternal(mesh, GL::Buffer::wrap(indices.id(), GL::Buffer::TargetHint::ElementArray), std::move(vertices), CompileFlag::NoWarnOnCustomAttributes);
}
GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer&& indices, GL::Buffer& vertices) {
return compileInternal(meshData, std::move(indices), GL::Buffer::wrap(vertices.id(), GL::Buffer::TargetHint::Array), CompileFlag::NoWarnOnCustomAttributes);
GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer&& indices, GL::Buffer& vertices) {
return compileInternal(mesh, std::move(indices), GL::Buffer::wrap(vertices.id(), GL::Buffer::TargetHint::Array), CompileFlag::NoWarnOnCustomAttributes);
}
GL::Mesh compile(const Trade::MeshData& meshData) {
return compileInternal(meshData, {});
GL::Mesh compile(const Trade::MeshData& mesh) {
return compileInternal(mesh, {});
}
GL::Mesh compile(const Trade::MeshData& meshData, CompileFlags flags) {
GL::Mesh compile(const Trade::MeshData& mesh, CompileFlags flags) {
/* If we want to generate normals, prepare a new mesh data and recurse,
with the flags unset */
if(meshData.primitive() == MeshPrimitive::Triangles && (flags & (CompileFlag::GenerateFlatNormals|CompileFlag::GenerateSmoothNormals))) {
CORRADE_ASSERT(meshData.attributeCount(Trade::MeshAttribute::Position),
if(mesh.primitive() == MeshPrimitive::Triangles && (flags & (CompileFlag::GenerateFlatNormals|CompileFlag::GenerateSmoothNormals))) {
CORRADE_ASSERT(mesh.attributeCount(Trade::MeshAttribute::Position),
"MeshTools::compile(): the mesh has no positions, can't generate normals", GL::Mesh{});
/* This could fire if we have 2D positions or for packed formats */
CORRADE_ASSERT(meshData.attributeFormat(Trade::MeshAttribute::Position) == VertexFormat::Vector3,
"MeshTools::compile(): can't generate normals for" << meshData.attributeFormat(Trade::MeshAttribute::Position) << "positions", GL::Mesh{});
CORRADE_ASSERT(mesh.attributeFormat(Trade::MeshAttribute::Position) == VertexFormat::Vector3,
"MeshTools::compile(): can't generate normals for" << mesh.attributeFormat(Trade::MeshAttribute::Position) << "positions", GL::Mesh{});
/* If the data already have a normal array, reuse its location,
otherwise mix in an extra one */
Trade::MeshAttributeData normalAttribute;
Containers::ArrayView<const Trade::MeshAttributeData> extra;
if(!meshData.hasAttribute(Trade::MeshAttribute::Normal)) {
if(!mesh.hasAttribute(Trade::MeshAttribute::Normal)) {
normalAttribute = Trade::MeshAttributeData{
Trade::MeshAttribute::Normal, VertexFormat::Vector3,
nullptr};
extra = {&normalAttribute, 1};
/* If we reuse a normal location, expect correct type */
} else CORRADE_ASSERT(meshData.attributeFormat(Trade::MeshAttribute::Normal) == VertexFormat::Vector3,
"MeshTools::compile(): can't generate normals into" << meshData.attributeFormat(Trade::MeshAttribute::Normal), GL::Mesh{});
} else CORRADE_ASSERT(mesh.attributeFormat(Trade::MeshAttribute::Normal) == VertexFormat::Vector3,
"MeshTools::compile(): can't generate normals into" << mesh.attributeFormat(Trade::MeshAttribute::Normal), GL::Mesh{});
/* If we want flat normals, we need to first duplicate everything using
the index buffer. Otherwise just interleave the potential extra
normal attribute in. */
Trade::MeshData generated{MeshPrimitive::Points, 0};
if(flags & CompileFlag::GenerateFlatNormals && meshData.isIndexed())
generated = duplicate(meshData, extra);
if(flags & CompileFlag::GenerateFlatNormals && mesh.isIndexed())
generated = duplicate(mesh, extra);
else
generated = interleave(meshData, extra);
generated = interleave(mesh, extra);
/* Generate the normals. If we don't have the index buffer, we can only
generate flat ones. */
if(flags & CompileFlag::GenerateFlatNormals || !meshData.isIndexed())
if(flags & CompileFlag::GenerateFlatNormals || !mesh.isIndexed())
generateFlatNormalsInto(
generated.attribute<Vector3>(Trade::MeshAttribute::Position),
generated.mutableAttribute<Vector3>(Trade::MeshAttribute::Normal));
@ -320,7 +320,7 @@ GL::Mesh compile(const Trade::MeshData& meshData, CompileFlags flags) {
flags &= ~(CompileFlag::GenerateFlatNormals|CompileFlag::GenerateSmoothNormals);
CORRADE_INTERNAL_ASSERT(!(flags & ~CompileFlag::NoWarnOnCustomAttributes));
return compileInternal(meshData, flags);
return compileInternal(mesh, flags);
}
#ifdef MAGNUM_BUILD_DEPRECATED
@ -555,16 +555,16 @@ CORRADE_IGNORE_DEPRECATED_POP
#endif
#ifndef MAGNUM_TARGET_GLES2
Containers::Pair<UnsignedInt, UnsignedInt> compiledPerVertexJointCount(const Trade::MeshData& meshData) {
Containers::Pair<UnsignedInt, UnsignedInt> compiledPerVertexJointCount(const Trade::MeshData& mesh) {
UnsignedInt primaryCount = 0, secondaryCount = 0;
for(UnsignedInt i = 0; i != meshData.attributeCount(); ++i) {
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
/* The mesh is expected to have the same count and array size of
JointIds and Weights, so it's enough to do it just for one of
them */
if(meshData.attributeName(i) != Trade::MeshAttribute::JointIds)
if(mesh.attributeName(i) != Trade::MeshAttribute::JointIds)
continue;
const UnsignedInt componentCount = meshData.attributeArraySize(i);
const UnsignedInt componentCount = mesh.attributeArraySize(i);
for(UnsignedInt j = 0; j < componentCount; j += 4) {
if(!primaryCount)
primaryCount = Math::min(componentCount - j, 4u);

18
src/Magnum/MeshTools/Compile.h

@ -167,7 +167,7 @@ to access them afterwards. For alternative solutions see the
@see @ref shaders-generic
*/
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, CompileFlags flags);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh, CompileFlags flags);
/**
* @overload
@ -176,7 +176,7 @@ MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, Compil
/* Separately because this one doesn't rely on duplicate() / interleave() /
generate*Normals() and thus the exe can be smaller when using this function
directly */
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh);
/**
@brief Compile mesh data using external buffers
@ -196,8 +196,8 @@ by the mesh or not:
@snippet MagnumMeshTools-gl.cpp compile-external-attributes
If @p meshData is not indexed, the @p indices parameter is ignored --- in that
case you can pass a @ref NoCreate "NoCreate"-d instance to avoid allocating an
If @p mesh is not indexed, the @p indices parameter is ignored --- in that case
you can pass a @ref NoCreate "NoCreate"-d instance to avoid allocating an
unnecessary OpenGL buffer object.
Compared to @ref compile(const Trade::MeshData&, CompileFlags), this function
@ -205,25 +205,25 @@ implicitly enables the @ref CompileFlag::NoWarnOnCustomAttributes flag,
assuming that custom attributes and attributes with implementation-specific
formats are explicitly handled on the application side.
*/
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer& indices, GL::Buffer& vertices);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer& indices, GL::Buffer& vertices);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer& indices, GL::Buffer&& vertices);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer& indices, GL::Buffer&& vertices);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer&& indices, GL::Buffer& vertices);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer&& indices, GL::Buffer& vertices);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer&& indices, GL::Buffer&& vertices);
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compile(const Trade::MeshData& mesh, GL::Buffer&& indices, GL::Buffer&& vertices);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@ -333,7 +333,7 @@ similarly with other builtin shaders.
support which is not available in WebGL 1.0, thus neither this function is
defined in WebGL 1.0 builds.
*/
MAGNUM_MESHTOOLS_EXPORT Containers::Pair<UnsignedInt, UnsignedInt> compiledPerVertexJointCount(const Trade::MeshData& meshData);
MAGNUM_MESHTOOLS_EXPORT Containers::Pair<UnsignedInt, UnsignedInt> compiledPerVertexJointCount(const Trade::MeshData& mesh);
#endif
}}

48
src/Magnum/MeshTools/CompressIndices.cpp

@ -125,61 +125,61 @@ Containers::Pair<Containers::Array<char>, MeshIndexType> compressIndices(const C
return compressIndices(indices, MeshIndexType::UnsignedShort, offset);
}
Trade::MeshData compressIndices(Trade::MeshData&& data, MeshIndexType atLeast) {
CORRADE_ASSERT(data.isIndexed(), "MeshTools::compressIndices(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
Trade::MeshData compressIndices(Trade::MeshData&& mesh, MeshIndexType atLeast) {
CORRADE_ASSERT(mesh.isIndexed(), "MeshTools::compressIndices(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
/* Transfer vertex data as-is, as those don't need any changes. Release if
possible. */
Containers::Array<char> vertexData;
const UnsignedInt vertexCount = data.vertexCount();
if(data.vertexDataFlags() & Trade::DataFlag::Owned)
vertexData = data.releaseVertexData();
const UnsignedInt vertexCount = mesh.vertexCount();
if(mesh.vertexDataFlags() & Trade::DataFlag::Owned)
vertexData = mesh.releaseVertexData();
else {
vertexData = Containers::Array<char>{NoInit, data.vertexData().size()};
Utility::copy(data.vertexData(), vertexData);
vertexData = Containers::Array<char>{NoInit, mesh.vertexData().size()};
Utility::copy(mesh.vertexData(), vertexData);
}
/* Compress the indices */
UnsignedInt offset;
Containers::Pair<Containers::Array<char>, MeshIndexType> result;
if(data.indexType() == MeshIndexType::UnsignedInt) {
auto indices = data.indices<UnsignedInt>();
if(mesh.indexType() == MeshIndexType::UnsignedInt) {
auto indices = mesh.indices<UnsignedInt>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedInt>(indices, atLeast, offset);
} else if(data.indexType() == MeshIndexType::UnsignedShort) {
auto indices = data.indices<UnsignedShort>();
} else if(mesh.indexType() == MeshIndexType::UnsignedShort) {
auto indices = mesh.indices<UnsignedShort>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedShort>(indices, atLeast, offset);
} else {
CORRADE_ASSERT(!isMeshIndexTypeImplementationSpecific(data.indexType()),
"MeshTools::compressIndices(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(data.indexType())),
CORRADE_ASSERT(!isMeshIndexTypeImplementationSpecific(mesh.indexType()),
"MeshTools::compressIndices(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(mesh.indexType())),
(Trade::MeshData{MeshPrimitive{}, 0}));
CORRADE_INTERNAL_ASSERT(data.indexType() == MeshIndexType::UnsignedByte);
auto indices = data.indices<UnsignedByte>();
CORRADE_INTERNAL_ASSERT(mesh.indexType() == MeshIndexType::UnsignedByte);
auto indices = mesh.indices<UnsignedByte>();
offset = Math::min(indices);
result = compressIndicesImplementation<UnsignedByte>(indices, atLeast, offset);
}
/* Recreate the attribute array */
const UnsignedInt newVertexCount = vertexCount - offset;
Containers::Array<Trade::MeshAttributeData> attributeData{data.attributeCount()};
Containers::Array<Trade::MeshAttributeData> attributeData{mesh.attributeCount()};
for(UnsignedInt i = 0, max = attributeData.size(); i != max; ++i) {
const UnsignedInt stride = data.attributeStride(i);
attributeData[i] = Trade::MeshAttributeData{data.attributeName(i),
data.attributeFormat(i),
Containers::StridedArrayView1D<const void>{vertexData, vertexData.data() + data.attributeOffset(i) + offset*stride, newVertexCount, stride},
data.attributeArraySize(i)};
const UnsignedInt stride = mesh.attributeStride(i);
attributeData[i] = Trade::MeshAttributeData{mesh.attributeName(i),
mesh.attributeFormat(i),
Containers::StridedArrayView1D<const void>{vertexData, vertexData.data() + mesh.attributeOffset(i) + offset*stride, newVertexCount, stride},
mesh.attributeArraySize(i)};
}
Trade::MeshIndexData indices{result.second(), result.first()};
return Trade::MeshData{data.primitive(), std::move(result.first()), indices,
return Trade::MeshData{mesh.primitive(), std::move(result.first()), indices,
std::move(vertexData), std::move(attributeData), newVertexCount};
}
Trade::MeshData compressIndices(const Trade::MeshData& data, MeshIndexType atLeast) {
Trade::MeshData compressIndices(const Trade::MeshData& mesh, MeshIndexType atLeast) {
/* Pass through to the && overload, which then decides whether to reuse
anything based on the DataFlags */
return compressIndices(reference(data), atLeast);
return compressIndices(reference(mesh), atLeast);
}
#ifdef MAGNUM_BUILD_DEPRECATED

4
src/Magnum/MeshTools/CompressIndices.h

@ -159,7 +159,7 @@ The mesh is expected to be indexed and the index type and the @p atLeast
parameter is expected to not be implementation-specific type.
@see @ref isMeshIndexTypeImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(const Trade::MeshData& data, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(const Trade::MeshData& mesh, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
/**
@brief Compress mesh data indices
@ -171,7 +171,7 @@ owned) to the returned instance instead of making a copy of it. Index and
attribute data are copied always.
@see @ref Trade::MeshData::vertexDataFlags()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(Trade::MeshData&& data, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData compressIndices(Trade::MeshData&& mesh, MeshIndexType atLeast = MeshIndexType::UnsignedShort);
#ifdef MAGNUM_BUILD_DEPRECATED
/**

30
src/Magnum/MeshTools/Duplicate.cpp

@ -80,14 +80,14 @@ void duplicateInto(const Containers::StridedArrayView2D<const char>& indices, co
}
}
Trade::MeshData duplicate(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {
CORRADE_ASSERT(data.isIndexed(), "MeshTools::duplicate(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
CORRADE_ASSERT(!isMeshIndexTypeImplementationSpecific(data.indexType()),
"MeshTools::duplicate(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(data.indexType())),
Trade::MeshData duplicate(const Trade::MeshData& mesh, const Containers::ArrayView<const Trade::MeshAttributeData> extra) {
CORRADE_ASSERT(mesh.isIndexed(), "MeshTools::duplicate(): mesh data not indexed", (Trade::MeshData{MeshPrimitive::Triangles, 0}));
CORRADE_ASSERT(!isMeshIndexTypeImplementationSpecific(mesh.indexType()),
"MeshTools::duplicate(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(mesh.indexType())),
(Trade::MeshData{MeshPrimitive{}, 0}));
#ifndef CORRADE_NO_ASSERT
for(std::size_t i = 0; i != data.attributeCount(); ++i) {
const VertexFormat format = data.attributeFormat(i);
for(std::size_t i = 0; i != mesh.attributeCount(); ++i) {
const VertexFormat format = mesh.attributeFormat(i);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format),
"MeshTools::duplicate(): attribute" << i << "has an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(format)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -101,14 +101,14 @@ Trade::MeshData duplicate(const Trade::MeshData& data, const Containers::ArrayVi
#endif
/* Calculate the layout */
Trade::MeshData layout = interleavedLayout(data, data.indexCount(), extra);
Trade::MeshData layout = interleavedLayout(mesh, mesh.indexCount(), extra);
/* Copy existing attributes to new locations */
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
duplicateInto(data.indices(), data.attribute(i), layout.mutableAttribute(i));
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i)
duplicateInto(mesh.indices(), mesh.attribute(i), layout.mutableAttribute(i));
/* Mix in the extra attributes */
UnsignedInt attributeIndex = data.attributeCount();
UnsignedInt attributeIndex = mesh.attributeCount();
for(UnsignedInt i = 0; i != extra.size(); ++i) {
/* Padding, ignore */
if(extra[i].format() == VertexFormat{}) continue;
@ -122,13 +122,13 @@ Trade::MeshData duplicate(const Trade::MeshData& data, const Containers::ArrayVi
/* Copy the attribute in, if it is non-empty, otherwise keep the
memory uninitialized */
if(extra[i].data()) {
CORRADE_ASSERT(extra[i].data().size() == data.vertexCount(),
"MeshTools::duplicate(): extra attribute" << i << "expected to have" << data.vertexCount() << "items but got" << extra[i].data().size(),
CORRADE_ASSERT(extra[i].data().size() == mesh.vertexCount(),
"MeshTools::duplicate(): extra attribute" << i << "expected to have" << mesh.vertexCount() << "items but got" << extra[i].data().size(),
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const Containers::StridedArrayView2D<const char> attributeData =
Containers::arrayCast<2, const char>(extra[i].data(),
vertexFormatSize(extra[i].format())*Math::max(extra[i].arraySize(), UnsignedShort{1}));
duplicateInto(data.indices(), attributeData, layout.mutableAttribute(attributeIndex));
duplicateInto(mesh.indices(), attributeData, layout.mutableAttribute(attributeIndex));
}
++attributeIndex;
@ -137,8 +137,8 @@ Trade::MeshData duplicate(const Trade::MeshData& data, const Containers::ArrayVi
return layout;
}
Trade::MeshData duplicate(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttributeData> extra) {
return duplicate(data, Containers::arrayView(extra));
Trade::MeshData duplicate(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttributeData> extra) {
return duplicate(mesh, Containers::arrayView(extra));
}
}}

12
src/Magnum/MeshTools/Duplicate.h

@ -135,8 +135,8 @@ MAGNUM_MESHTOOLS_EXPORT void duplicateInto(const Containers::StridedArrayView2D<
@brief Duplicate indexed mesh data
@m_since{2020,06}
Returns a copy of @p data that's not indexed and has all attributes interleaved
and duplicated according to @p data's index buffer. The @p extra attributes, if
Returns a copy of @p mesh that's not indexed and has all attributes interleaved
and duplicated according to @p mesh's index buffer. The @p extra attributes, if
any, are duplicated and interleaved together with existing attributes (or, in
case the attribute view is empty, only the corresponding space for given
attribute type is reserved, with memory left uninitialized). The data layouting
@ -144,21 +144,21 @@ is done by @ref interleavedLayout(), see its documentation for detailed
behavior description. Note that offset-only @ref Trade::MeshAttributeData
instances are not supported in the @p extra array.
Expects that @p data is indexed with a non-implementation-specific index type
Expects that @p mesh is indexed with a non-implementation-specific index type
and each attribute in @p extra has either the same amount of elements as
@p data vertex count (*not* index count) or has none. All attributes are
@p mesh vertex count (*not* index count) or has none. All attributes are
expected to not have an implementation-specific format.
@see @ref isMeshIndexTypeImplementationSpecific(),
@ref isVertexFormatImplementationSpecific(),
@ref Trade::MeshData::attributeData()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttributeData> extra = {});
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& mesh, Containers::ArrayView<const Trade::MeshAttributeData> extra = {});
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttributeData> extra);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData duplicate(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttributeData> extra);
template<class IndexType, class T> inline void duplicateInto(const Containers::StridedArrayView1D<const IndexType>& indices, const Containers::StridedArrayView1D<const T>& data, const Containers::StridedArrayView1D<T>& out) {
duplicateInto(indices, Containers::arrayCast<2, const char>(data), Containers::arrayCast<2, char>(out));

148
src/Magnum/MeshTools/FilterAttributes.cpp

@ -49,7 +49,7 @@ bool hasAttribute(const Containers::ArrayView<const UnsignedInt> attributes, con
}
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttribute> attributes) {
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, const Containers::ArrayView<const Trade::MeshAttribute> attributes) {
/* Not asserting here for existence of attributes since that'd be another
O(n^2) operation */
/** @todo but that's not consistent with the ID-based variant, or maybe do
@ -58,10 +58,10 @@ Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containe
/* Pick just attributes from the list */
Containers::Array<Trade::MeshAttributeData> filtered;
arrayReserve(filtered, data.attributeCount());
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(hasAttribute(attributes, data.attributeName(i)))
arrayAppend(filtered, data.attributeData(i));
arrayReserve(filtered, mesh.attributeCount());
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
if(hasAttribute(attributes, mesh.attributeName(i)))
arrayAppend(filtered, mesh.attributeData(i));
}
/* Convert back to a default deleter to make this usable in plugins */
@ -72,37 +72,37 @@ Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containe
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
{}, data.indexData(), indices,
{}, data.vertexData(), std::move(filtered),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
{}, mesh.indexData(), indices,
{}, mesh.vertexData(), std::move(filtered),
mesh.vertexCount()};
}
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes) {
return filterOnlyAttributes(data, Containers::arrayView(attributes));
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttribute> attributes) {
return filterOnlyAttributes(mesh, Containers::arrayView(attributes));
}
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containers::ArrayView<const UnsignedInt> attributes) {
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, const Containers::ArrayView<const UnsignedInt> attributes) {
#ifndef CORRADE_NO_ASSERT
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < data.attributeCount(),
"MeshTools::filterOnlyAttributes(): index" << i << "out of range for" << data.attributeCount() << "attributes",
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < mesh.attributeCount(),
"MeshTools::filterOnlyAttributes(): index" << i << "out of range for" << mesh.attributeCount() << "attributes",
(Trade::MeshData{MeshPrimitive{}, 0}));
#endif
/* Pick just attributes from the list */
Containers::Array<Trade::MeshAttributeData> filtered;
arrayReserve(filtered, data.attributeCount());
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
arrayReserve(filtered, mesh.attributeCount());
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
if(hasAttribute(attributes, i))
arrayAppend(filtered, data.attributeData(i));
arrayAppend(filtered, mesh.attributeData(i));
}
/* Convert back to a default deleter to make this usable in plugins */
@ -113,25 +113,25 @@ Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, const Containe
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
{}, data.indexData(), indices,
{}, data.vertexData(), std::move(filtered),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
{}, mesh.indexData(), indices,
{}, mesh.vertexData(), std::move(filtered),
mesh.vertexCount()};
}
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes) {
return filterOnlyAttributes(data, Containers::arrayView(attributes));
Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, std::initializer_list<UnsignedInt> attributes) {
return filterOnlyAttributes(mesh, Containers::arrayView(attributes));
}
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttribute> attributes) {
Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, const Containers::ArrayView<const Trade::MeshAttribute> attributes) {
/* Not asserting here for existence of attributes since that'd be another
O(n^2) operation */
/** @todo but that's not consistent with the ID-based variant, or maybe do
@ -140,10 +140,10 @@ Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Contai
/* Pick just attributes from the list */
Containers::Array<Trade::MeshAttributeData> filtered;
arrayReserve(filtered, data.attributeCount());
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(!hasAttribute(attributes, data.attributeName(i)))
arrayAppend(filtered, data.attributeData(i));
arrayReserve(filtered, mesh.attributeCount());
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
if(!hasAttribute(attributes, mesh.attributeName(i)))
arrayAppend(filtered, mesh.attributeData(i));
}
/* Convert back to a default deleter to make this usable in plugins */
@ -154,37 +154,37 @@ Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Contai
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
{}, data.indexData(), indices,
{}, data.vertexData(), std::move(filtered),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
{}, mesh.indexData(), indices,
{}, mesh.vertexData(), std::move(filtered),
mesh.vertexCount()};
}
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes) {
return filterExceptAttributes(data, Containers::arrayView(attributes));
Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttribute> attributes) {
return filterExceptAttributes(mesh, Containers::arrayView(attributes));
}
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Containers::ArrayView<const UnsignedInt> attributes) {
Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, const Containers::ArrayView<const UnsignedInt> attributes) {
#ifndef CORRADE_NO_ASSERT
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < data.attributeCount(),
"MeshTools::filterExceptAttributes(): index" << i << "out of range for" << data.attributeCount() << "attributes",
for(const UnsignedInt i: attributes) CORRADE_ASSERT(i < mesh.attributeCount(),
"MeshTools::filterExceptAttributes(): index" << i << "out of range for" << mesh.attributeCount() << "attributes",
(Trade::MeshData{MeshPrimitive{}, 0}));
#endif
/* Pick just attributes from the list */
Containers::Array<Trade::MeshAttributeData> filtered;
arrayReserve(filtered, data.attributeCount());
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
arrayReserve(filtered, mesh.attributeCount());
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
if(!hasAttribute(attributes, i))
arrayAppend(filtered, data.attributeData(i));
arrayAppend(filtered, mesh.attributeData(i));
}
/* Convert back to a default deleter to make this usable in plugins */
@ -195,22 +195,22 @@ Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, const Contai
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
{}, data.indexData(), indices,
{}, data.vertexData(), std::move(filtered),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
{}, mesh.indexData(), indices,
{}, mesh.vertexData(), std::move(filtered),
mesh.vertexCount()};
}
Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes) {
return filterExceptAttributes(data, Containers::arrayView(attributes));
Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, std::initializer_list<UnsignedInt> attributes) {
return filterExceptAttributes(mesh, Containers::arrayView(attributes));
}
}}

30
src/Magnum/MeshTools/FilterAttributes.h

@ -41,10 +41,10 @@ namespace Magnum { namespace MeshTools {
@brief Filter a mesh to contain only the selected subset of named attributes
@m_since_latest
Returns a non-owning reference to the vertex and index buffer from @p data with
Returns a non-owning reference to the vertex and index buffer from @p mesh with
only the attributes that are listed in @p attributes. The index buffer, if
present, is left untouched. Attributes from the list that are not present in
@p data are skipped. All duplicates of a listed attribute are kept --- if you
@p mesh are skipped. All duplicates of a listed attribute are kept --- if you
want a different behavior, use the @ref filterOnlyAttributes(const Trade::MeshData&, Containers::ArrayView<const UnsignedInt>)
overload and pick attributes by their IDs instead.
@ -54,19 +54,19 @@ the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<cons
without @ref InterleaveFlag::PreserveInterleavedAttributes set.
@see @ref reference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttribute> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, Containers::ArrayView<const Trade::MeshAttribute> attributes);
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttribute> attributes);
/**
@brief Filter a mesh to contain only the selected subset of attributes
@m_since_latest
Returns a non-owning reference to the vertex and index buffer from @p data with
Returns a non-owning reference to the vertex and index buffer from @p mesh with
only the attribute IDs listed in @p attributes. IDs specified more than once
don't result in given attribute being added multiple times. The index buffer,
if present, is left untouched. All attribute IDs are expected to be smaller
@ -78,44 +78,44 @@ the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<cons
without @ref InterleaveFlag::PreserveInterleavedAttributes set.
@see @ref reference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, Containers::ArrayView<const UnsignedInt> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, Containers::ArrayView<const UnsignedInt> attributes);
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterOnlyAttributes(const Trade::MeshData& mesh, std::initializer_list<UnsignedInt> attributes);
/**
@brief Filter a mesh to contain everything except the selected subset of named attributes
@m_since_latest
Returns a non-owning reference to the vertex and index buffer from @p data with
Returns a non-owning reference to the vertex and index buffer from @p mesh with
only the attributes that are not listed in @p attributes. The index buffer, if
present, is left untouched. Attributes from the list that are not present in
@p data are skipped. All duplicates of a listed attribute are removed --- if
@p mesh are skipped. All duplicates of a listed attribute are removed --- if
you want a different behavior, use the @ref filterExceptAttributes(const Trade::MeshData&, Containers::ArrayView<const UnsignedInt>)
overload and pick attributes by their IDs instead. If @p attributes is empty,
the behavior is equivalent to @ref reference().
This function only operates on the attribute metadata --- if you'd like to have
the vertex data repacked to contain just the remaining attributes as well, pass
the vertex mesh repacked to contain just the remaining attributes as well, pass
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()"
without @ref InterleaveFlag::PreserveInterleavedAttributes set.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttribute> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, Containers::ArrayView<const Trade::MeshAttribute> attributes);
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttribute> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttribute> attributes);
/**
@brief Filter a mesh to contain everything except the selected subset of attributes
@m_since_latest
Returns a non-owning reference to the vertex and index buffer from @p data with
Returns a non-owning reference to the vertex and index buffer from @p mesh with
only the attribute IDs that are not listed in @p attributes. IDs specified
multiple times behave like if specified just once. The index buffer, if
present, is left untouched. All attribute IDs are expected to be smaller than
@ -127,13 +127,13 @@ the vertex data repacked to contain just the remaining attributes as well, pass
the output to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags) "interleave()"
without @ref InterleaveFlag::PreserveInterleavedAttributes set.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, Containers::ArrayView<const UnsignedInt> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, Containers::ArrayView<const UnsignedInt> attributes);
/**
* @overload
* @m_since_latest
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& data, std::initializer_list<UnsignedInt> attributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData filterExceptAttributes(const Trade::MeshData& mesh, std::initializer_list<UnsignedInt> attributes);
}}

66
src/Magnum/MeshTools/GenerateIndices.cpp

@ -576,77 +576,77 @@ void generateQuadIndicesInto(const Containers::StridedArrayView1D<const Vector3>
return generateQuadIndicesIntoImplementation(positions, quads, output);
}
Trade::MeshData generateIndices(Trade::MeshData&& data) {
CORRADE_ASSERT(!data.isIndexed() || !isMeshIndexTypeImplementationSpecific(data.indexType()),
"MeshTools::generateIndices(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(data.indexType())),
Trade::MeshData generateIndices(Trade::MeshData&& mesh) {
CORRADE_ASSERT(!mesh.isIndexed() || !isMeshIndexTypeImplementationSpecific(mesh.indexType()),
"MeshTools::generateIndices(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(mesh.indexType())),
(Trade::MeshData{MeshPrimitive{}, 0}));
const UnsignedInt vertexCount = data.vertexCount();
const UnsignedInt vertexCount = mesh.vertexCount();
#ifndef CORRADE_NO_ASSERT
UnsignedInt minVertexCount;
if(data.primitive() == MeshPrimitive::LineStrip ||
data.primitive() == MeshPrimitive::LineLoop) {
if(mesh.primitive() == MeshPrimitive::LineStrip ||
mesh.primitive() == MeshPrimitive::LineLoop) {
minVertexCount = 2;
} else if(data.primitive() == MeshPrimitive::TriangleStrip ||
data.primitive() == MeshPrimitive::TriangleFan) {
} else if(mesh.primitive() == MeshPrimitive::TriangleStrip ||
mesh.primitive() == MeshPrimitive::TriangleFan) {
minVertexCount = 3;
} else CORRADE_ASSERT_UNREACHABLE("MeshTools::generateIndices(): invalid primitive" << data.primitive(),
} else CORRADE_ASSERT_UNREACHABLE("MeshTools::generateIndices(): invalid primitive" << mesh.primitive(),
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
CORRADE_ASSERT(vertexCount == 0 || vertexCount >= minVertexCount,
"MeshTools::generateIndices(): expected either zero or at least" << minVertexCount << "vertices for" << data.primitive() << Debug::nospace << ", got" << vertexCount,
"MeshTools::generateIndices(): expected either zero or at least" << minVertexCount << "vertices for" << mesh.primitive() << Debug::nospace << ", got" << vertexCount,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
#endif
/* Transfer vertex / attribute data as-is, as those don't need any changes.
Release if possible. */
Containers::Array<char> vertexData;
if(data.vertexDataFlags() & Trade::DataFlag::Owned)
vertexData = data.releaseVertexData();
if(mesh.vertexDataFlags() & Trade::DataFlag::Owned)
vertexData = mesh.releaseVertexData();
else {
vertexData = Containers::Array<char>{NoInit, data.vertexData().size()};
Utility::copy(data.vertexData(), vertexData);
vertexData = Containers::Array<char>{NoInit, mesh.vertexData().size()};
Utility::copy(mesh.vertexData(), vertexData);
}
/* Recreate the attribute array with views on the new vertexData */
/** @todo if the vertex data were moved and this array is owned, it
wouldn't need to be recreated, but the logic is a bit complex */
Containers::Array<Trade::MeshAttributeData> attributeData{data.attributeCount()};
Containers::Array<Trade::MeshAttributeData> attributeData{mesh.attributeCount()};
for(UnsignedInt i = 0, max = attributeData.size(); i != max; ++i) {
attributeData[i] = Trade::MeshAttributeData{data.attributeName(i),
data.attributeFormat(i),
Containers::StridedArrayView1D<const void>{vertexData, vertexData.data() + data.attributeOffset(i), vertexCount, data.attributeStride(i)},
data.attributeArraySize(i)};
attributeData[i] = Trade::MeshAttributeData{mesh.attributeName(i),
mesh.attributeFormat(i),
Containers::StridedArrayView1D<const void>{vertexData, vertexData.data() + mesh.attributeOffset(i), vertexCount, mesh.attributeStride(i)},
mesh.attributeArraySize(i)};
}
/* Generate the index array */
MeshPrimitive primitive;
Containers::Array<char> indexData;
if(data.primitive() == MeshPrimitive::LineStrip) {
if(mesh.primitive() == MeshPrimitive::LineStrip) {
primitive = MeshPrimitive::Lines;
indexData = Containers::Array<char>{NoInit, 2*(Math::max(vertexCount, 1u) - 1)*sizeof(UnsignedInt)};
if(data.isIndexed())
generateLineStripIndicesInto(data.indices(), Containers::arrayCast<UnsignedInt>(indexData));
if(mesh.isIndexed())
generateLineStripIndicesInto(mesh.indices(), Containers::arrayCast<UnsignedInt>(indexData));
else
generateLineStripIndicesInto(vertexCount, Containers::arrayCast<UnsignedInt>(indexData));
} else if(data.primitive() == MeshPrimitive::LineLoop) {
} else if(mesh.primitive() == MeshPrimitive::LineLoop) {
primitive = MeshPrimitive::Lines;
indexData = Containers::Array<char>{NoInit, 2*vertexCount*sizeof(UnsignedInt)};
if(data.isIndexed())
generateLineLoopIndicesInto(data.indices(), Containers::arrayCast<UnsignedInt>(indexData));
if(mesh.isIndexed())
generateLineLoopIndicesInto(mesh.indices(), Containers::arrayCast<UnsignedInt>(indexData));
else
generateLineLoopIndicesInto(vertexCount, Containers::arrayCast<UnsignedInt>(indexData));
} else if(data.primitive() == MeshPrimitive::TriangleStrip) {
} else if(mesh.primitive() == MeshPrimitive::TriangleStrip) {
primitive = MeshPrimitive::Triangles;
indexData = Containers::Array<char>{NoInit, 3*(Math::max(vertexCount, 2u) - 2)*sizeof(UnsignedInt)};
if(data.isIndexed())
generateTriangleStripIndicesInto(data.indices(), Containers::arrayCast<UnsignedInt>(indexData));
if(mesh.isIndexed())
generateTriangleStripIndicesInto(mesh.indices(), Containers::arrayCast<UnsignedInt>(indexData));
else
generateTriangleStripIndicesInto(vertexCount, Containers::arrayCast<UnsignedInt>(indexData));
} else if(data.primitive() == MeshPrimitive::TriangleFan) {
} else if(mesh.primitive() == MeshPrimitive::TriangleFan) {
primitive = MeshPrimitive::Triangles;
indexData = Containers::Array<char>{NoInit, 3*(Math::max(vertexCount, 2u) - 2)*sizeof(UnsignedInt)};
if(data.isIndexed())
generateTriangleFanIndicesInto(data.indices(), Containers::arrayCast<UnsignedInt>(indexData));
if(mesh.isIndexed())
generateTriangleFanIndicesInto(mesh.indices(), Containers::arrayCast<UnsignedInt>(indexData));
else
generateTriangleFanIndicesInto(vertexCount, Containers::arrayCast<UnsignedInt>(indexData));
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
@ -656,10 +656,10 @@ Trade::MeshData generateIndices(Trade::MeshData&& data) {
std::move(vertexData), std::move(attributeData), vertexCount};
}
Trade::MeshData generateIndices(const Trade::MeshData& data) {
Trade::MeshData generateIndices(const Trade::MeshData& mesh) {
/* Pass through to the && overload, which then decides whether to reuse
anything based on the DataFlags */
return generateIndices(reference(data));
return generateIndices(reference(mesh));
}
}}

4
src/Magnum/MeshTools/GenerateIndices.h

@ -508,12 +508,12 @@ MAGNUM_MESHTOOLS_EXPORT Trade::MeshData generateIndices(const Trade::MeshData& m
@m_since{2020,06}
Compared to @ref generateIndices(const Trade::MeshData&) this function can
transfer ownership of @p data vertex buffer (in case it is owned) to the
transfer ownership of @p mesh vertex buffer (in case it is owned) to the
returned instance instead of making a copy of it. Attribute data is copied
always.
@see @ref Trade::MeshData::vertexDataFlags()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData generateIndices(Trade::MeshData&& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData generateIndices(Trade::MeshData&& mesh);
}}

162
src/Magnum/MeshTools/Interleave.cpp

@ -36,41 +36,41 @@ namespace Magnum { namespace MeshTools {
namespace {
inline std::size_t attributeSize(const Trade::MeshData& data, UnsignedInt i) {
return vertexFormatSize(data.attributeFormat(i))*Math::max(data.attributeArraySize(i), UnsignedShort{1});
inline std::size_t attributeSize(const Trade::MeshData& mesh, UnsignedInt i) {
return vertexFormatSize(mesh.attributeFormat(i))*Math::max(mesh.attributeArraySize(i), UnsignedShort{1});
}
inline std::size_t attributeSize(const Trade::MeshAttributeData& data) {
return vertexFormatSize(data.format())*Math::max(data.arraySize(), UnsignedShort{1});
inline std::size_t attributeSize(const Trade::MeshAttributeData& mesh) {
return vertexFormatSize(mesh.format())*Math::max(mesh.arraySize(), UnsignedShort{1});
}
Containers::Optional<Containers::StridedArrayView2D<const char>> interleavedDataInternal(const Trade::MeshData& data) {
Containers::Optional<Containers::StridedArrayView2D<const char>> interleavedDataInternal(const Trade::MeshData& mesh) {
/* There is no attributes, return a zero-sized view to indicate a success */
if(!data.attributeCount())
return Containers::StridedArrayView2D<const char>{data.vertexData(), {data.vertexCount(), 0}};
if(!mesh.attributeCount())
return Containers::StridedArrayView2D<const char>{mesh.vertexData(), {mesh.vertexCount(), 0}};
/* Technically zero and negative strides *may* also be categorized as
interleaved if they are all the same, but it causes way too many
problems especially when used within interleavedLayout() etc. May
tackle properly later. */
const Int stride = data.attributeStride(0);
const Int stride = mesh.attributeStride(0);
if(stride <= 0) return Containers::NullOpt;
std::size_t minOffset = ~std::size_t{};
std::size_t maxOffset = 0;
bool hasImplementationSpecificVertexFormat = false;
for(UnsignedInt i = 0; i != data.attributeCount(); ++i) {
if(data.attributeStride(i) != stride) return Containers::NullOpt;
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i) {
if(mesh.attributeStride(i) != stride) return Containers::NullOpt;
const std::size_t offset = data.attributeOffset(i);
const std::size_t offset = mesh.attributeOffset(i);
minOffset = Math::min(minOffset, offset);
/* If the attribute has implementation-specific format, remember that
for later and optimistically use size of 1 byte for calculations */
std::size_t size;
if(isVertexFormatImplementationSpecific(data.attributeFormat(i))) {
if(isVertexFormatImplementationSpecific(mesh.attributeFormat(i))) {
hasImplementationSpecificVertexFormat = true;
size = 1;
} else size = attributeSize(data, i);
} else size = attributeSize(mesh, i);
maxOffset = Math::max(maxOffset, offset + size);
}
@ -87,26 +87,26 @@ Containers::Optional<Containers::StridedArrayView2D<const char>> interleavedData
if(maxOffset - minOffset > UnsignedInt(stride)) return Containers::NullOpt;
return Containers::StridedArrayView2D<const char>{
data.vertexData(), data.vertexData().data() + minOffset,
{data.vertexCount(), maxOffset - minOffset},
mesh.vertexData(), mesh.vertexData().data() + minOffset,
{mesh.vertexCount(), maxOffset - minOffset},
{std::ptrdiff_t(stride), 1}};
}
}
bool isInterleaved(const Trade::MeshData& data) {
return !!interleavedDataInternal(data);
bool isInterleaved(const Trade::MeshData& mesh) {
return !!interleavedDataInternal(mesh);
}
Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& data) {
auto out = interleavedDataInternal(data);
Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& mesh) {
auto out = interleavedDataInternal(mesh);
CORRADE_ASSERT(out, "MeshTools::interleavedData(): the mesh is not interleaved", {});
return *out;
}
Containers::StridedArrayView2D<char> interleavedMutableData(Trade::MeshData& data) {
Containers::StridedArrayView2D<const char> out = interleavedData(data);
CORRADE_ASSERT(data.vertexDataFlags() & Trade::DataFlag::Mutable,
Containers::StridedArrayView2D<char> interleavedMutableData(Trade::MeshData& mesh) {
Containers::StridedArrayView2D<const char> out = interleavedData(mesh);
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::interleavedMutableData(): vertex data is not mutable", {});
return Containers::StridedArrayView2D<char>{
{nullptr, ~std::size_t{}}, /* to sidestep the range assertions */
@ -116,32 +116,32 @@ Containers::StridedArrayView2D<char> interleavedMutableData(Trade::MeshData& dat
namespace Implementation {
Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&& data, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&& mesh, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
/* Nothing to do here, bye! */
if(!data.attributeCount() && extra.isEmpty()) return {};
if(!mesh.attributeCount() && extra.isEmpty()) return {};
/* If we're not told to preserve the layout, treat the mesh as
noninterleaved always, forcing a repack. Otherwise check if it's already
interleaved. */
const bool interleaved = flags >= InterleaveFlag::PreserveInterleavedAttributes && isInterleaved(data);
const bool interleaved = flags >= InterleaveFlag::PreserveInterleavedAttributes && isInterleaved(mesh);
/* If the mesh is already interleaved, use the original stride to
preserve all padding, but remove the initial offset. Otherwise calculate
a tightly-packed stride. */
std::size_t stride;
std::size_t minOffset;
if(interleaved && data.attributeCount()) {
stride = data.attributeStride(0);
if(interleaved && mesh.attributeCount()) {
stride = mesh.attributeStride(0);
minOffset = ~std::size_t{};
for(UnsignedInt i = 0, max = data.attributeCount(); i != max; ++i)
minOffset = Math::min(minOffset, data.attributeOffset(i));
for(UnsignedInt i = 0, max = mesh.attributeCount(); i != max; ++i)
minOffset = Math::min(minOffset, mesh.attributeOffset(i));
} else {
stride = 0;
minOffset = 0;
for(UnsignedInt i = 0, max = data.attributeCount(); i != max; ++i) {
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(data.attributeFormat(i)),
"MeshTools::interleavedLayout(): attribute" << i << "has an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(data.attributeFormat(i))), {});
stride += attributeSize(data, i);
for(UnsignedInt i = 0, max = mesh.attributeCount(); i != max; ++i) {
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(mesh.attributeFormat(i)),
"MeshTools::interleavedLayout(): attribute" << i << "has an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(mesh.attributeFormat(i))), {});
stride += attributeSize(mesh, i);
}
}
@ -166,11 +166,11 @@ Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&&
can take over the ownership and avoid an allocation. Otherwise we
allocate a new array and copy the prefix over so we can just patch the
data array later. */
const UnsignedInt originalAttributeCount = data.attributeCount();
const UnsignedInt originalAttributeCount = mesh.attributeCount();
const UnsignedInt originalAttributeStride = originalAttributeCount ?
data.attributeStride(0) : 0;
mesh.attributeStride(0) : 0;
Containers::Array<Trade::MeshAttributeData> originalAttributeData =
data.releaseAttributeData();
mesh.releaseAttributeData();
Containers::Array<Trade::MeshAttributeData> attributeData;
if(!extraAttributeCount && !originalAttributeData.deleter())
attributeData = std::move(originalAttributeData);
@ -183,7 +183,7 @@ Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&&
preserve relative attribute offsets, otherwise pack tightly. */
std::size_t offset = 0;
for(UnsignedInt i = 0; i != originalAttributeCount; ++i) {
if(interleaved) offset = attributeData[i].offset(data.vertexData()) - minOffset;
if(interleaved) offset = attributeData[i].offset(mesh.vertexData()) - minOffset;
attributeData[i] = Trade::MeshAttributeData{
attributeData[i].name(), attributeData[i].format(),
@ -219,13 +219,13 @@ Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&&
}
Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Containers::Array<Trade::MeshAttributeData> attributeData = Implementation::interleavedLayout(std::move(data), extra, flags);
Trade::MeshData interleavedLayout(Trade::MeshData&& mesh, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Containers::Array<Trade::MeshAttributeData> attributeData = Implementation::interleavedLayout(std::move(mesh), extra, flags);
/* If there are no attributes, bail -- return an empty mesh with desired
vertex count but nothing else */
if(!attributeData)
return Trade::MeshData{data.primitive(), vertexCount};
return Trade::MeshData{mesh.primitive(), vertexCount};
/* Allocate new data array */
Containers::Array<char> vertexData{NoInit, attributeData[0].stride()*vertexCount};
@ -241,53 +241,53 @@ Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vert
attribute.arraySize()};
}
return Trade::MeshData{data.primitive(), std::move(vertexData), std::move(attributeData)};
return Trade::MeshData{mesh.primitive(), std::move(vertexData), std::move(attributeData)};
}
Trade::MeshData interleavedLayout(Trade::MeshData&& data, const UnsignedInt vertexCount, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleavedLayout(std::move(data), vertexCount, Containers::arrayView(extra), flags);
Trade::MeshData interleavedLayout(Trade::MeshData&& mesh, const UnsignedInt vertexCount, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleavedLayout(std::move(mesh), vertexCount, Containers::arrayView(extra), flags);
}
Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Trade::MeshData interleavedLayout(const Trade::MeshData& mesh, const UnsignedInt vertexCount, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
/* Pass through to the && overload, which then decides whether to reuse
anything based on the DataFlags */
return interleavedLayout(reference(data), vertexCount, extra, flags);
return interleavedLayout(reference(mesh), vertexCount, extra, flags);
}
Trade::MeshData interleavedLayout(const Trade::MeshData& data, const UnsignedInt vertexCount, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleavedLayout(data, vertexCount, Containers::arrayView(extra), flags);
Trade::MeshData interleavedLayout(const Trade::MeshData& mesh, const UnsignedInt vertexCount, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleavedLayout(mesh, vertexCount, Containers::arrayView(extra), flags);
}
Trade::MeshData interleave(Trade::MeshData&& data, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Trade::MeshData interleave(Trade::MeshData&& mesh, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
/* Transfer the indices unchanged, in case the mesh is indexed */
Containers::Array<char> indexData;
Trade::MeshIndexData indices;
if(data.isIndexed()) {
const MeshIndexType indexType = data.indexType();
if(mesh.isIndexed()) {
const MeshIndexType indexType = mesh.indexType();
/* If we can steal the data and we're allowed to preserve a strided
layout or it's tightly packed, do the steal */
if((data.indexDataFlags() & Trade::DataFlag::Owned) && ((flags & InterleaveFlag::PreserveStridedIndices) || (!isMeshIndexTypeImplementationSpecific(indexType) && data.indexStride() == Int(meshIndexTypeSize(indexType))))) {
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && ((flags & InterleaveFlag::PreserveStridedIndices) || (!isMeshIndexTypeImplementationSpecific(indexType) && mesh.indexStride() == Int(meshIndexTypeSize(indexType))))) {
indices = Trade::MeshIndexData{indexType,
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
indexData = data.releaseIndexData();
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
indexData = mesh.releaseIndexData();
/* Otherwise, if we can't steal the data but we're told to preserve
strided indices, make a full copy including any extra offsets and
paddings */
} else if(flags & InterleaveFlag::PreserveStridedIndices) {
indexData = Containers::Array<char>{NoInit, data.indexData().size()};
indexData = Containers::Array<char>{NoInit, mesh.indexData().size()};
indices = Trade::MeshIndexData{indexType,
Containers::StridedArrayView1D<const void>{
indexData,
indexData.data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
Utility::copy(data.indexData(), indexData);
indexData.data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
Utility::copy(mesh.indexData(), indexData);
/* Otherwise, make a tightly packed copy, in which case we can't have
an implementation-specific index type */
@ -297,48 +297,48 @@ Trade::MeshData interleave(Trade::MeshData&& data, const Containers::ArrayView<c
(Trade::MeshData{MeshPrimitive{}, 0}));
const std::size_t indexTypeSize = meshIndexTypeSize(indexType);
indexData = Containers::Array<char>{NoInit, data.indexCount()*indexTypeSize};
indexData = Containers::Array<char>{NoInit, mesh.indexCount()*indexTypeSize};
Containers::StridedArrayView2D<char> out{indexData,
{data.indexCount(), indexTypeSize},
{mesh.indexCount(), indexTypeSize},
{std::ptrdiff_t(indexTypeSize), 1}};
indices = Trade::MeshIndexData{out};
Utility::copy(data.indices(), out);
Utility::copy(mesh.indices(), out);
}
}
/* If we're not told to preserve the layout, treat the mesh as
noninterleaved always, forcing a repack. Otherwise check if it's already
interleaved. */
const bool interleaved = flags >= InterleaveFlag::PreserveInterleavedAttributes && isInterleaved(data);
const UnsignedInt vertexCount = data.vertexCount();
const bool interleaved = flags >= InterleaveFlag::PreserveInterleavedAttributes && isInterleaved(mesh);
const UnsignedInt vertexCount = mesh.vertexCount();
/* If the mesh is already interleaved and we don't have anything extra,
steal that data as well */
Containers::Array<char> vertexData;
Containers::Array<Trade::MeshAttributeData> attributeData;
if(interleaved && extra.isEmpty() && (data.vertexDataFlags() & Trade::DataFlag::Owned)) {
attributeData = data.releaseAttributeData();
vertexData = data.releaseVertexData();
if(interleaved && extra.isEmpty() && (mesh.vertexDataFlags() & Trade::DataFlag::Owned)) {
attributeData = mesh.releaseAttributeData();
vertexData = mesh.releaseVertexData();
/* Otherwise do it the hard way */
} else {
/* Calculate the layout. Can't std::move() the data in to avoid copying
the attribute array as we need the original attributes below. */
Trade::MeshData layout = interleavedLayout(data, vertexCount, extra, flags);
Trade::MeshData layout = interleavedLayout(mesh, vertexCount, extra, flags);
#ifdef CORRADE_GRACEFUL_ASSERT
/* If interleavedLayout() gracefully asserted and returned no
attributes (but the original had some), exit right away to not blow
up on something else later. Sorry, yes, this is shitty. */
if(!layout.attributeCount() && (data.attributeCount() || extra.size()))
if(!layout.attributeCount() && (mesh.attributeCount() || extra.size()))
return Trade::MeshData{MeshPrimitive::Points, 0};
#endif
/* Copy existing attributes to new locations */
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
Utility::copy(data.attribute(i), layout.mutableAttribute(i));
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i)
Utility::copy(mesh.attribute(i), layout.mutableAttribute(i));
/* Mix in the extra attributes */
UnsignedInt attributeIndex = data.attributeCount();
UnsignedInt attributeIndex = mesh.attributeCount();
for(UnsignedInt i = 0; i != extra.size(); ++i) {
/* Padding, ignore */
if(extra[i].format() == VertexFormat{}) continue;
@ -368,22 +368,22 @@ Trade::MeshData interleave(Trade::MeshData&& data, const Containers::ArrayView<c
attributeData = layout.releaseAttributeData();
}
return Trade::MeshData{data.primitive(), std::move(indexData), indices,
return Trade::MeshData{mesh.primitive(), std::move(indexData), indices,
std::move(vertexData), std::move(attributeData), vertexCount};
}
Trade::MeshData interleave(Trade::MeshData&& data, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleave(std::move(data), Containers::arrayView(extra), flags);
Trade::MeshData interleave(Trade::MeshData&& mesh, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleave(std::move(mesh), Containers::arrayView(extra), flags);
}
Trade::MeshData interleave(const Trade::MeshData& data, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
Trade::MeshData interleave(const Trade::MeshData& mesh, const Containers::ArrayView<const Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
/* Pass through to the && overload, which then decides whether to reuse
anything based on the DataFlags */
return interleave(reference(data), extra, flags);
return interleave(reference(mesh), extra, flags);
}
Trade::MeshData interleave(const Trade::MeshData& data, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleave(std::move(data), Containers::arrayView(extra), flags);
Trade::MeshData interleave(const Trade::MeshData& mesh, const std::initializer_list<Trade::MeshAttributeData> extra, const InterleaveFlags flags) {
return interleave(std::move(mesh), Containers::arrayView(extra), flags);
}
}}

46
src/Magnum/MeshTools/Interleave.h

@ -204,7 +204,7 @@ non-interleaved.
@see @ref Trade::MeshData::attributeStride(),
@ref Trade::MeshData::attributeOffset(), @ref interleavedData()
*/
MAGNUM_MESHTOOLS_EXPORT bool isInterleaved(const Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT bool isInterleaved(const Trade::MeshData& mesh);
/**
@brief Type-erased view on interleaved mesh data
@ -219,7 +219,7 @@ count to cover all interleaved attributes, including any padding between them
but not before or after.
@see @ref isInterleaved()
*/
MAGNUM_MESHTOOLS_EXPORT Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Containers::StridedArrayView2D<const char> interleavedData(const Trade::MeshData& mesh);
/**
@brief Mutable type-erased view on interleaved mesh data
@ -229,16 +229,16 @@ Same as @ref interleavedData(), but returns a mutable view. Expects that the
mesh is interleaved and vertex data is mutable.
@see @ref isInterleaved(), @ref Trade::MeshData::vertexDataFlags()
*/
MAGNUM_MESHTOOLS_EXPORT Containers::StridedArrayView2D<char> interleavedMutableData(Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Containers::StridedArrayView2D<char> interleavedMutableData(Trade::MeshData& mesh);
/**
@brief Create an interleaved mesh layout
@m_since{2020,06}
Returns a @ref Trade::MeshData instance with its vertex data allocated for
@p vertexCount vertices containing attributes from both @p data and @p extra
@p vertexCount vertices containing attributes from both @p mesh and @p extra
interleaved together. No data is actually copied, only an interleaved layout is
created. If @p data is already interleaved according to @ref isInterleaved()
created. If @p mesh is already interleaved according to @ref isInterleaved()
and @ref InterleaveFlag::PreserveInterleavedAttributes is set in @p flags,
keeps the attributes in the same layout, potentially extending them with
@p extra. The @p extra attributes, if any, are interleaved together with
@ -265,42 +265,42 @@ This function will unconditionally allocate a new array to store all
@ref Trade::MeshAttributeData, use @ref interleavedLayout(Trade::MeshData&&, UnsignedInt, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags)
to avoid that allocation.
All attributes in both @p data and @p extra are expected to not have an
implementation-specific format, except for @p data attributes in case @p data
All attributes in both @p mesh and @p extra are expected to not have an
implementation-specific format, except for @p mesh attributes in case @p mesh
is already interleaved, then the layout is untouched.
@see @ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& data, UnsignedInt vertexCount, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& mesh, UnsignedInt vertexCount, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& data, UnsignedInt vertexCount, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(const Trade::MeshData& mesh, UnsignedInt vertexCount, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Create an interleaved mesh layout
@m_since{2020,06}
Compared to @ref interleavedLayout(const Trade::MeshData&, UnsignedInt, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags)
this function can reuse the @ref Trade::MeshAttributeData array from @p data
this function can reuse the @ref Trade::MeshAttributeData array from @p mesh
instead of allocating a new one if there are no attributes passed in @p extra,
the attribute array is owned by the mesh and
@ref InterleaveFlag::PreserveInterleavedAttributes is set in @p flags.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(Trade::MeshData&& data, UnsignedInt vertexCount, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(Trade::MeshData&& mesh, UnsignedInt vertexCount, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(Trade::MeshData&& data, UnsignedInt vertexCount, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleavedLayout(Trade::MeshData&& mesh, UnsignedInt vertexCount, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Interleave mesh data
@m_since{2020,06}
Returns a copy of @p data with all attributes interleaved. The @p extra
Returns a copy of @p mesh with all attributes interleaved. The @p extra
attributes, if any, are interleaved together with existing attributes (or, in
case the attribute view is empty, only the corresponding space for given
attribute type is reserved, with memory left uninitialized). The data layouting
@ -314,32 +314,32 @@ implementation-specific type. Otherwise the behavior depends on presence of
@ref InterleaveFlag::PreserveStridedIndices.
Expects that each attribute in @p extra has either the same amount of elements
as @p data vertex count or has none. This function will unconditionally make a
copy of all data even if @p data is already interleaved and needs no change,
as @p mesh vertex count or has none. This function will unconditionally make a
copy of all data even if @p mesh is already interleaved and needs no change,
use @ref interleave(Trade::MeshData&&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags)
to avoid that copy.
All attributes in both @p data and @p extra are expected to not have an
implementation-specific format, except for @p data attributes in case @p data
All attributes in both @p mesh and @p extra are expected to not have an
implementation-specific format, except for @p mesh attributes in case @p data
is already interleaved, then the layout is untouched.
@see @ref isInterleaved(), @ref isMeshIndexTypeImplementationSpecific(),
@ref isVertexFormatImplementationSpecific(),
@ref Trade::MeshData::attributeData()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(const Trade::MeshData& data, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(const Trade::MeshData& mesh, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(const Trade::MeshData& data, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(const Trade::MeshData& mesh, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Interleave mesh data
@m_since{2020,06}
Compared to @ref interleave(const Trade::MeshData&, Containers::ArrayView<const Trade::MeshAttributeData>, InterleaveFlags)
this function can transfer ownership of @p data index buffer (in case it is
this function can transfer ownership of @p mesh index buffer (in case it is
owned) and vertex buffer (in case it is owned, already interleaved, there's no
@p extra attributes and @ref InterleaveFlag::PreserveInterleavedAttributes is
set in @p flags) to the returned instance instead of making copies of them.
@ -347,18 +347,18 @@ set in @p flags) to the returned instance instead of making copies of them.
@ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeData()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(Trade::MeshData&& data, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(Trade::MeshData&& mesh, Containers::ArrayView<const Trade::MeshAttributeData> extra = {}, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
* @overload
* @m_since{2020,06}
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(Trade::MeshData&& data, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData interleave(Trade::MeshData&& mesh, std::initializer_list<Trade::MeshAttributeData> extra, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
namespace Implementation {
/* Used internally by interleavedLayout() and concatenate() */
MAGNUM_MESHTOOLS_EXPORT Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&& data, Containers::ArrayView<const Trade::MeshAttributeData> extra, InterleaveFlags flags);
MAGNUM_MESHTOOLS_EXPORT Containers::Array<Trade::MeshAttributeData> interleavedLayout(Trade::MeshData&& mesh, Containers::ArrayView<const Trade::MeshAttributeData> extra, InterleaveFlags flags);
}

90
src/Magnum/MeshTools/Reference.cpp

@ -31,28 +31,28 @@
namespace Magnum { namespace MeshTools {
Trade::MeshData reference(const Trade::MeshData& data) {
Trade::MeshData reference(const Trade::MeshData& mesh) {
/* Can't do just Trade::MeshIndexData{data.indices()} as that would discard
implementation-specific types. And can't do
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
{}, data.indexData(), indices,
{}, data.vertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
{}, mesh.indexData(), indices,
{}, mesh.vertexData(), Trade::meshAttributeDataNonOwningArray(mesh.attributeData()),
mesh.vertexCount()};
}
Trade::MeshData mutableReference(Trade::MeshData& data) {
CORRADE_ASSERT((data.indexDataFlags() & Trade::DataFlag::Mutable) && (data.vertexDataFlags() & Trade::DataFlag::Mutable),
Trade::MeshData mutableReference(Trade::MeshData& mesh) {
CORRADE_ASSERT((mesh.indexDataFlags() & Trade::DataFlag::Mutable) && (mesh.vertexDataFlags() & Trade::DataFlag::Mutable),
"MeshTools::mutableReference(): data not mutable",
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -61,57 +61,57 @@ Trade::MeshData mutableReference(Trade::MeshData& data) {
Trade::meshIndexData{data.indexType(), view}
because asking for index type would assert on non-indexed meshes. */
Trade::MeshIndexData indices;
if(data.isIndexed()) indices = Trade::MeshIndexData{
data.indexType(),
if(mesh.isIndexed()) indices = Trade::MeshIndexData{
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
data.indexData(),
data.indexData().data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
return Trade::MeshData{data.primitive(),
Trade::DataFlag::Mutable, data.mutableIndexData(), indices,
Trade::DataFlag::Mutable, data.mutableVertexData(), Trade::meshAttributeDataNonOwningArray(data.attributeData()),
data.vertexCount()};
mesh.indexData(),
mesh.indexData().data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
return Trade::MeshData{mesh.primitive(),
Trade::DataFlag::Mutable, mesh.mutableIndexData(), indices,
Trade::DataFlag::Mutable, mesh.mutableVertexData(), Trade::meshAttributeDataNonOwningArray(mesh.attributeData()),
mesh.vertexCount()};
}
Trade::MeshData owned(const Trade::MeshData& data) {
return owned(reference(data));
Trade::MeshData owned(const Trade::MeshData& mesh) {
return owned(reference(mesh));
}
Trade::MeshData owned(Trade::MeshData&& data) {
Trade::MeshData owned(Trade::MeshData&& mesh) {
/** @todo copy only the actually used range instead of the whole thing? */
/* If index data are already owned, move them to the output. This works
without any extra effort also for non-indexed meshes. */
Containers::Array<char> indexData;
Trade::MeshIndexData indices;
if(data.indexDataFlags() & Trade::DataFlag::Owned) {
indices = Trade::MeshIndexData{data.indices()};
indexData = data.releaseIndexData();
if(mesh.indexDataFlags() & Trade::DataFlag::Owned) {
indices = Trade::MeshIndexData{mesh.indices()};
indexData = mesh.releaseIndexData();
/* Otherwise copy them, if the mesh is indexed. If not, the
default-constructed instances are fine. */
} else if(data.isIndexed()) {
indexData = Containers::Array<char>{NoInit, data.indexData().size()};
} else if(mesh.isIndexed()) {
indexData = Containers::Array<char>{NoInit, mesh.indexData().size()};
indices = Trade::MeshIndexData{
data.indexType(),
mesh.indexType(),
Containers::StridedArrayView1D<const void>{
indexData,
indexData.data() + data.indexOffset(),
data.indexCount(),
data.indexStride()}};
Utility::copy(data.indexData(), indexData);
indexData.data() + mesh.indexOffset(),
mesh.indexCount(),
mesh.indexStride()}};
Utility::copy(mesh.indexData(), indexData);
}
/* If vertex data are already owned, move them to the output. Because
releasing them will clear vertex count, save that in advance, save also
original vertex data view for attribute offset calculation */
const UnsignedInt vertexCount = data.vertexCount();
const Containers::ArrayView<const char> originalVertexData = data.vertexData();
const UnsignedInt vertexCount = mesh.vertexCount();
const Containers::ArrayView<const char> originalVertexData = mesh.vertexData();
Containers::Array<char> vertexData;
if(data.vertexDataFlags() & Trade::DataFlag::Owned) {
vertexData = data.releaseVertexData();
if(mesh.vertexDataFlags() & Trade::DataFlag::Owned) {
vertexData = mesh.releaseVertexData();
/* Otherwise copy them */
} else {
@ -122,12 +122,12 @@ Trade::MeshData owned(Trade::MeshData&& data) {
/* There's no way to know if attribute data are owned until we release
them and check the deleter, but releasing them makes it impossible to
use the convenience MeshData APIs, so we have to do the hard way. */
Containers::Array<Trade::MeshAttributeData> originalAttributeData = data.releaseAttributeData();
Containers::Array<Trade::MeshAttributeData> originalAttributeData = mesh.releaseAttributeData();
/* If the attribute data are owned *and* the vertex data weren't copied,
we can reuse the original array in its entirety */
Containers::Array<Trade::MeshAttributeData> attributeData;
if(!originalAttributeData.deleter() && (data.vertexDataFlags() & Trade::DataFlag::Owned)) {
if(!originalAttributeData.deleter() && (mesh.vertexDataFlags() & Trade::DataFlag::Owned)) {
attributeData = std::move(originalAttributeData);
/* Otherwise we have to allocate a new one and re-route the attributes to
@ -147,7 +147,7 @@ Trade::MeshData owned(Trade::MeshData&& data) {
}
}
return Trade::MeshData{data.primitive(),
return Trade::MeshData{mesh.primitive(),
std::move(indexData), indices,
std::move(vertexData), std::move(attributeData),
vertexCount};

14
src/Magnum/MeshTools/Reference.h

@ -41,11 +41,11 @@ namespace Magnum { namespace MeshTools {
The returned instance has empty @ref Trade::MeshData::indexDataFlags() and
@ref Trade::MeshData::vertexDataFlags() and references attribute data from the
@p data as well. The function performs no allocation or data copy. Use
@p mesh as well. The function performs no allocation or data copy. Use
@ref owned() for an inverse operation.
@see @ref mutableReference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData reference(const Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData reference(const Trade::MeshData& mesh);
/**
@brief Create a mutable reference on a @ref Trade::MeshData
@ -54,10 +54,10 @@ MAGNUM_MESHTOOLS_EXPORT Trade::MeshData reference(const Trade::MeshData& data);
The returned instance has @ref Trade::MeshData::indexDataFlags() and
@ref Trade::MeshData::vertexDataFlags() set to @ref Trade::DataFlag::Mutable.
The function performs no allocation or data copy. Use @ref owned() for an
inverse operation. Expects that @p data is mutable.
inverse operation. Expects that @p mesh is mutable.
@see @ref reference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData mutableReference(Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData mutableReference(Trade::MeshData& mesh);
/**
@brief Create an owned @ref Trade::MeshData
@ -67,12 +67,12 @@ The returned instance owns its index, vertex and attribute data --- both
@ref Trade::MeshData::indexDataFlags() and
@ref Trade::MeshData::vertexDataFlags() have @ref Trade::DataFlag::Mutable and
@ref Trade::DataFlag::Owned set. This function unconditionally does an
allocation and a copy even if the @p data is already owned, use
allocation and a copy even if the @p mesh is already owned, use
@ref owned(Trade::MeshData&&) to make an owned copy only if the instance isn't
already owned.
@see @ref reference(), @ref mutableReference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData owned(const Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData owned(const Trade::MeshData& mesh);
/**
@brief Create an owned @ref Trade::MeshData, if not already
@ -86,7 +86,7 @@ already owned are simply moved to the output, otherwise the data get copied
into newly allocated arrays.
@see @ref reference(), @ref mutableReference()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData owned(Trade::MeshData&& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData owned(Trade::MeshData&& mesh);
}}

20
src/Magnum/MeshTools/RemoveDuplicates.cpp

@ -397,13 +397,13 @@ std::size_t removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayVi
return removeDuplicatesFuzzyIndexedInPlaceImplementation(indices, data, epsilon);
}
Trade::MeshData removeDuplicates(const Trade::MeshData& data) {
CORRADE_ASSERT(data.attributeCount(),
Trade::MeshData removeDuplicates(const Trade::MeshData& mesh) {
CORRADE_ASSERT(mesh.attributeCount(),
"MeshTools::removeDuplicates(): can't remove duplicates in an attributeless mesh",
(Trade::MeshData{MeshPrimitive::Points, 0}));
#ifndef CORRADE_NO_ASSERT
for(std::size_t i = 0; i != data.attributeCount(); ++i) {
const VertexFormat format = data.attributeFormat(i);
for(std::size_t i = 0; i != mesh.attributeCount(); ++i) {
const VertexFormat format = mesh.attributeFormat(i);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(format),
"MeshTools::removeDuplicates(): attribute" << i << "has an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(format)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -412,8 +412,8 @@ Trade::MeshData removeDuplicates(const Trade::MeshData& data) {
/* This has to be checked before passing the data to interleave() as there
it would die also, but with a confusing function name in the message */
CORRADE_ASSERT(!data.isIndexed() || !isMeshIndexTypeImplementationSpecific(data.indexType()),
"MeshTools::removeDuplicates(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(data.indexType())),
CORRADE_ASSERT(!mesh.isIndexed() || !isMeshIndexTypeImplementationSpecific(mesh.indexType()),
"MeshTools::removeDuplicates(): mesh has an implementation-specific index type" << reinterpret_cast<void*>(meshIndexTypeUnwrap(mesh.indexType())),
(Trade::MeshData{MeshPrimitive{}, 0}));
/* Turn the passed data into an interleaved owned mutable instance we can
@ -424,7 +424,7 @@ Trade::MeshData removeDuplicates(const Trade::MeshData& data) {
which is set by default, otherwise random padding bytes or filtered-out
attributes may contribute to the non-uniqueness of particular
elements. */
Trade::MeshData ownedInterleaved = owned(interleave(data, {}, InterleaveFlags{}));
Trade::MeshData ownedInterleaved = owned(interleave(mesh, {}, InterleaveFlags{}));
/* Because the interleaved mesh was forced to be repacked, the vertex data
should span the whole stride -- this is relied on in the attribute
@ -472,15 +472,15 @@ Trade::MeshData removeDuplicates(const Trade::MeshData& data) {
uniqueVertexCount};
}
Trade::MeshData removeDuplicatesFuzzy(const Trade::MeshData& data, const Float floatEpsilon, const Double doubleEpsilon) {
CORRADE_ASSERT(data.attributeCount(),
Trade::MeshData removeDuplicatesFuzzy(const Trade::MeshData& mesh, const Float floatEpsilon, const Double doubleEpsilon) {
CORRADE_ASSERT(mesh.attributeCount(),
"MeshTools::removeDuplicatesFuzzy(): can't remove duplicates in an attributeless mesh",
(Trade::MeshData{MeshPrimitive::Points, 0}));
/* Turn the passed data into an owned mutable instance we can operate on.
There's a chance the original data are already like this, in which case
this will be just a passthrough. */
Trade::MeshData owned = MeshTools::owned(std::move(data));
Trade::MeshData owned = MeshTools::owned(std::move(mesh));
/* Allocate an interleaved index array for all vertices times all
attributes */

4
src/Magnum/MeshTools/RemoveDuplicates.h

@ -310,7 +310,7 @@ copies and interleaves the input vertex and index data.
@see @ref isMeshIndexTypeImplementationSpecific(),
@ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData removeDuplicates(const Trade::MeshData& data);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData removeDuplicates(const Trade::MeshData& mesh);
/**
@brief Remove mesh data duplicates with fuzzy comparison for floating-point attributes
@ -323,7 +323,7 @@ on floating-point attributes. For attributes with a known range (such as
direction) the @p floatEpsilon / @p doubleEpsilon is scaled appropriately,
otherwise it's scaled to calculated value range.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData removeDuplicatesFuzzy(const Trade::MeshData& data, Float floatEpsilon = Math::TypeTraits<Float>::epsilon(), Double doubleEpsilon = Math::TypeTraits<Double>::epsilon());
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData removeDuplicatesFuzzy(const Trade::MeshData& mesh, Float floatEpsilon = Math::TypeTraits<Float>::epsilon(), Double doubleEpsilon = Math::TypeTraits<Double>::epsilon());
#ifdef MAGNUM_BUILD_DEPRECATED
template<class Vector> std::vector<UnsignedInt> removeDuplicates(std::vector<Vector>& data, typename Vector::Type epsilon) {

196
src/Magnum/MeshTools/Transform.cpp

@ -33,12 +33,12 @@
namespace Magnum { namespace MeshTools {
Trade::MeshData transform2D(const Trade::MeshData& data, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = data.findAttributeId(Trade::MeshAttribute::Position, id);
Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2D(): the mesh has no positions with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const VertexFormat positionAttributeFormat = data.attributeFormat(*positionAttributeId);
const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat),
"MeshTools::transform2D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -50,9 +50,9 @@ Trade::MeshData transform2D(const Trade::MeshData& data, const Matrix3& transfor
position attribute format, if needed. Not using Utility::copy() here as
the view returned by attributeData() might have offset-only attributes
which interleave() doesn't want. */
Containers::Array<Trade::MeshAttributeData> attributes{data.attributeCount()};
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
attributes[i] = data.attributeData(i);
Containers::Array<Trade::MeshAttributeData> attributes{mesh.attributeCount()};
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i)
attributes[i] = mesh.attributeData(i);
/* If the position attribute isn't in a desired format, replace it with an
empty placeholder that we'll unpack the data into */
@ -61,73 +61,73 @@ Trade::MeshData transform2D(const Trade::MeshData& data, const Matrix3& transfor
/* Create the output mesh, making more room for the full formats if
necessary */
Trade::MeshData out = interleave(filterOnlyAttributes(data, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
Trade::MeshData out = interleave(filterOnlyAttributes(mesh, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
/* If the position attribute wasn't in a desired format, unpack it */
if(positionAttributeFormat != VertexFormat::Vector2)
data.positions2DInto(out.mutableAttribute<Vector2>(*positionAttributeId), id);
mesh.positions2DInto(out.mutableAttribute<Vector2>(*positionAttributeId), id);
/* Delegate to the in-place implementation and return */
transform2DInPlace(out, transformation, id);
return out;
}
Trade::MeshData transform2D(Trade::MeshData&& data, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the
assert here again. */
if((data.indexDataFlags() & Trade::DataFlag::Owned) &&
(data.vertexDataFlags() & Trade::DataFlag::Owned) &&
data.attributeCount(Trade::MeshAttribute::Position) > id &&
data.attributeFormat(Trade::MeshAttribute::Position, id) == VertexFormat::Vector2)
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
mesh.attributeCount(Trade::MeshAttribute::Position) > id &&
mesh.attributeFormat(Trade::MeshAttribute::Position, id) == VertexFormat::Vector2)
{
transform2DInPlace(data, transformation, id);
return std::move(data);
transform2DInPlace(mesh, transformation, id);
return std::move(mesh);
}
/* Otherwise delegate to the function that does all the copying and format
expansion */
return transform2D(data, transformation, id, flags);
return transform2D(mesh, transformation, id, flags);
}
void transform2DInPlace(Trade::MeshData& data, const Matrix3& transformation, const UnsignedInt id) {
CORRADE_ASSERT(data.vertexDataFlags() & Trade::DataFlag::Mutable,
void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transform2DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> positionAttributeId = data.findAttributeId(Trade::MeshAttribute::Position, id);
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2DInPlace(): the mesh has no positions with index" << id, );
CORRADE_ASSERT(data.attributeFormat(*positionAttributeId) == VertexFormat::Vector2,
"MeshTools::transform2DInPlace(): expected" << VertexFormat::Vector2 << "positions but got" << data.attributeFormat(*positionAttributeId), );
CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2,
"MeshTools::transform2DInPlace(): expected" << VertexFormat::Vector2 << "positions but got" << mesh.attributeFormat(*positionAttributeId), );
/** @todo this needs a proper batch implementation */
for(Vector2& position: data.mutableAttribute<Vector2>(*positionAttributeId))
for(Vector2& position: mesh.mutableAttribute<Vector2>(*positionAttributeId))
position = transformation.transformPoint(position);
}
Trade::MeshData transform3D(const Trade::MeshData& data, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = data.findAttributeId(Trade::MeshAttribute::Position, id);
Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3D(): the mesh has no positions with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const VertexFormat positionAttributeFormat = data.attributeFormat(*positionAttributeId);
const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat),
"MeshTools::transform3D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
CORRADE_ASSERT(vertexFormatComponentCount(positionAttributeFormat) == 3,
"MeshTools::transform3D(): expected 3D positions but got" << positionAttributeFormat,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const Containers::Optional<UnsignedInt> tangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = data.findAttributeId(Trade::MeshAttribute::Normal, id);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id);
/* Copy original attributes to a mutable array so we can update the
position attribute format, if needed. Not using Utility::copy() here as
the view returned by attributeData() might have offset-only attributes
which interleave() doesn't want. */
Containers::Array<Trade::MeshAttributeData> attributes{data.attributeCount()};
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
attributes[i] = data.attributeData(i);
Containers::Array<Trade::MeshAttributeData> attributes{mesh.attributeCount()};
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i)
attributes[i] = mesh.attributeData(i);
/* If the position/TBN attributes aren't in a desired format, replace them
with an empty placeholder that we'll unpack the data into */
@ -136,18 +136,18 @@ Trade::MeshData transform3D(const Trade::MeshData& data, const Matrix4& transfor
VertexFormat tangentAttributeFormat{};
VertexFormat desiredTangentVertexFormat{};
if(tangentAttributeId) {
tangentAttributeFormat = data.attributeFormat(*tangentAttributeId);
tangentAttributeFormat = mesh.attributeFormat(*tangentAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(tangentAttributeFormat),
"MeshTools::transform3D(): tangents have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(tangentAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
desiredTangentVertexFormat = vertexFormatComponentCount(data.attributeFormat(*tangentAttributeId)) == 4 ?
desiredTangentVertexFormat = vertexFormatComponentCount(mesh.attributeFormat(*tangentAttributeId)) == 4 ?
VertexFormat::Vector4 : VertexFormat::Vector3;
if(tangentAttributeFormat != desiredTangentVertexFormat)
attributes[*tangentAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, desiredTangentVertexFormat, nullptr};
}
VertexFormat bitangentAttributeFormat{};
if(bitangentAttributeId) {
bitangentAttributeFormat = data.attributeFormat(*bitangentAttributeId);
bitangentAttributeFormat = mesh.attributeFormat(*bitangentAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(bitangentAttributeFormat),
"MeshTools::transform3D(): bitangents have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(bitangentAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -156,7 +156,7 @@ Trade::MeshData transform3D(const Trade::MeshData& data, const Matrix4& transfor
}
VertexFormat normalAttributeFormat{};
if(normalAttributeId) {
normalAttributeFormat = data.attributeFormat(*normalAttributeId);
normalAttributeFormat = mesh.attributeFormat(*normalAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(normalAttributeFormat),
"MeshTools::transform3D(): normals have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(normalAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -166,76 +166,76 @@ Trade::MeshData transform3D(const Trade::MeshData& data, const Matrix4& transfor
/* Create the output mesh, making more room for the full formats if
necessary */
Trade::MeshData out = interleave(filterOnlyAttributes(data, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
Trade::MeshData out = interleave(filterOnlyAttributes(mesh, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
/* If the position/TBN attributes weren't in a desired format, unpack them */
if(positionAttributeFormat != VertexFormat::Vector3)
data.positions3DInto(out.mutableAttribute<Vector3>(*positionAttributeId), id);
mesh.positions3DInto(out.mutableAttribute<Vector3>(*positionAttributeId), id);
if(tangentAttributeId && tangentAttributeFormat != desiredTangentVertexFormat) {
if(desiredTangentVertexFormat == VertexFormat::Vector4) {
data.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id);
data.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id);
mesh.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id);
mesh.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id);
} else {
data.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id);
mesh.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id);
}
}
if(bitangentAttributeId && bitangentAttributeFormat != VertexFormat::Vector3)
data.bitangentsInto(out.mutableAttribute<Vector3>(*bitangentAttributeId), id);
mesh.bitangentsInto(out.mutableAttribute<Vector3>(*bitangentAttributeId), id);
if(normalAttributeId && normalAttributeFormat != VertexFormat::Vector3)
data.normalsInto(out.mutableAttribute<Vector3>(*normalAttributeId), id);
mesh.normalsInto(out.mutableAttribute<Vector3>(*normalAttributeId), id);
/* Delegate to the in-place implementation and return */
transform3DInPlace(out, transformation, id);
return out;
}
Trade::MeshData transform3D(Trade::MeshData&& data, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the
assert here again. */
const Containers::Optional<UnsignedInt> positionAttributeId = data.findAttributeId(Trade::MeshAttribute::Position, id);
const Containers::Optional<UnsignedInt> tangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = data.findAttributeId(Trade::MeshAttribute::Normal, id);
if((data.indexDataFlags() & Trade::DataFlag::Owned) &&
(data.vertexDataFlags() & Trade::DataFlag::Owned) &&
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id);
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
positionAttributeId &&
data.attributeFormat(*positionAttributeId) == VertexFormat::Vector3 &&
(!tangentAttributeId || data.attributeFormat(*tangentAttributeId) == VertexFormat::Vector3 || data.attributeFormat(*tangentAttributeId) == VertexFormat::Vector4) &&
(!bitangentAttributeId || data.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3) &&
(!normalAttributeId || data.attributeFormat(*normalAttributeId) == VertexFormat::Vector3))
mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3 &&
(!tangentAttributeId || mesh.attributeFormat(*tangentAttributeId) == VertexFormat::Vector3 || mesh.attributeFormat(*tangentAttributeId) == VertexFormat::Vector4) &&
(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3) &&
(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3))
{
transform3DInPlace(data, transformation, id);
return std::move(data);
transform3DInPlace(mesh, transformation, id);
return std::move(mesh);
}
/* Otherwise delegate to the function that does all the copying and format
expansion */
return transform3D(data, transformation, id, flags);
return transform3D(mesh, transformation, id, flags);
}
void transform3DInPlace(Trade::MeshData& data, const Matrix4& transformation, const UnsignedInt id) {
CORRADE_ASSERT(data.vertexDataFlags() & Trade::DataFlag::Mutable,
void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transform3DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> positionAttributeId = data.findAttributeId(Trade::MeshAttribute::Position, id);
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3DInPlace(): the mesh has no positions with index" << id, );
CORRADE_ASSERT(data.attributeFormat(*positionAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "positions but got" << data.attributeFormat(*positionAttributeId), );
const Containers::Optional<UnsignedInt> tangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Tangent, id);
const VertexFormat tangentAttributeFormat = tangentAttributeId ? data.attributeFormat(*tangentAttributeId) : VertexFormat{};
CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "positions but got" << mesh.attributeFormat(*positionAttributeId), );
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id);
const VertexFormat tangentAttributeFormat = tangentAttributeId ? mesh.attributeFormat(*tangentAttributeId) : VertexFormat{};
CORRADE_ASSERT(!tangentAttributeId || tangentAttributeFormat == VertexFormat::Vector3 || tangentAttributeFormat == VertexFormat::Vector4,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "or" << VertexFormat::Vector4 << "tangents but got" << data.attributeFormat(*tangentAttributeId), );
const Containers::Optional<UnsignedInt> bitangentAttributeId = data.findAttributeId(Trade::MeshAttribute::Bitangent, id);
CORRADE_ASSERT(!bitangentAttributeId || data.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "bitangents but got" << data.attributeFormat(*bitangentAttributeId), );
const Containers::Optional<UnsignedInt> normalAttributeId = data.findAttributeId(Trade::MeshAttribute::Normal, id);
CORRADE_ASSERT(!normalAttributeId || data.attributeFormat(*normalAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "normals but got" << data.attributeFormat(*normalAttributeId), );
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "or" << VertexFormat::Vector4 << "tangents but got" << mesh.attributeFormat(*tangentAttributeId), );
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id);
CORRADE_ASSERT(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "bitangents but got" << mesh.attributeFormat(*bitangentAttributeId), );
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id);
CORRADE_ASSERT(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "normals but got" << mesh.attributeFormat(*normalAttributeId), );
/** @todo this needs a proper batch implementation */
for(Vector3& position: data.mutableAttribute<Vector3>(*positionAttributeId))
for(Vector3& position: mesh.mutableAttribute<Vector3>(*positionAttributeId))
position = transformation.transformPoint(position);
/* If no other attributes are present, nothing to do */
@ -246,28 +246,28 @@ void transform3DInPlace(Trade::MeshData& data, const Matrix4& transformation, co
if(tangentAttributeId) {
/** @todo this needs a proper batch implementation */
if(tangentAttributeFormat == VertexFormat::Vector3)
for(Vector3& tangent: data.mutableAttribute<Vector3>(*tangentAttributeId))
for(Vector3& tangent: mesh.mutableAttribute<Vector3>(*tangentAttributeId))
tangent = normalMatrix*tangent;
else for(Vector4& tangent: data.mutableAttribute<Vector4>(*tangentAttributeId)) {
else for(Vector4& tangent: mesh.mutableAttribute<Vector4>(*tangentAttributeId)) {
tangent.xyz() = normalMatrix*tangent.xyz();
/** @todo figure out the fourth component, probably has to get
flipped when the scale changes handedness? */
}
}
/** @todo this needs a proper batch implementation */
if(bitangentAttributeId) for(Vector3& bitangent: data.mutableAttribute<Vector3>(*bitangentAttributeId))
if(bitangentAttributeId) for(Vector3& bitangent: mesh.mutableAttribute<Vector3>(*bitangentAttributeId))
bitangent = normalMatrix*bitangent;
/** @todo this needs a proper batch implementation */
if(normalAttributeId) for(Vector3& normal: data.mutableAttribute<Vector3>(*normalAttributeId))
if(normalAttributeId) for(Vector3& normal: mesh.mutableAttribute<Vector3>(*normalAttributeId))
normal = normalMatrix*normal;
}
Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& data, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = data.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id);
Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id);
CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
const VertexFormat textureCoordinateAttributeFormat = data.attributeFormat(*textureCoordinateAttributeId);
const VertexFormat textureCoordinateAttributeFormat = mesh.attributeFormat(*textureCoordinateAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(textureCoordinateAttributeFormat),
"MeshTools::transformTextureCoordinates2D(): texture coordinates have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(textureCoordinateAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0}));
@ -276,9 +276,9 @@ Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& data, const
position attribute format, if needed. Not using Utility::copy() here as
the view returned by attributeData() might have offset-only attributes
which interleave() doesn't want. */
Containers::Array<Trade::MeshAttributeData> attributes{data.attributeCount()};
for(UnsignedInt i = 0; i != data.attributeCount(); ++i)
attributes[i] = data.attributeData(i);
Containers::Array<Trade::MeshAttributeData> attributes{mesh.attributeCount()};
for(UnsignedInt i = 0; i != mesh.attributeCount(); ++i)
attributes[i] = mesh.attributeData(i);
/* If the position attribute isn't in a desired format, replace it with an
empty placeholder that we'll unpack the data into */
@ -287,47 +287,47 @@ Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& data, const
/* Create the output mesh, making more room for the full formats if
necessary */
Trade::MeshData out = interleave(filterOnlyAttributes(data, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
Trade::MeshData out = interleave(filterOnlyAttributes(mesh, Containers::ArrayView<const UnsignedInt>{}), attributes, flags);
/* If the position attribute wasn't in a desired format, unpack it */
if(data.attributeFormat(*textureCoordinateAttributeId) != VertexFormat::Vector2)
data.textureCoordinates2DInto(out.mutableAttribute<Vector2>(*textureCoordinateAttributeId), id);
if(mesh.attributeFormat(*textureCoordinateAttributeId) != VertexFormat::Vector2)
mesh.textureCoordinates2DInto(out.mutableAttribute<Vector2>(*textureCoordinateAttributeId), id);
/* Delegate to the in-place implementation and return */
transformTextureCoordinates2DInPlace(out, transformation, id);
return out;
}
Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& data, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the
assert here again. */
if((data.indexDataFlags() & Trade::DataFlag::Owned) &&
(data.vertexDataFlags() & Trade::DataFlag::Owned) &&
data.attributeCount(Trade::MeshAttribute::TextureCoordinates) > id &&
data.attributeFormat(Trade::MeshAttribute::TextureCoordinates, id) == VertexFormat::Vector2)
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
mesh.attributeCount(Trade::MeshAttribute::TextureCoordinates) > id &&
mesh.attributeFormat(Trade::MeshAttribute::TextureCoordinates, id) == VertexFormat::Vector2)
{
transformTextureCoordinates2DInPlace(data, transformation, id);
return std::move(data);
transformTextureCoordinates2DInPlace(mesh, transformation, id);
return std::move(mesh);
}
/* Otherwise delegate to the function that does all the copying and format
expansion */
return transformTextureCoordinates2D(data, transformation, id, flags);
return transformTextureCoordinates2D(mesh, transformation, id, flags);
}
void transformTextureCoordinates2DInPlace(Trade::MeshData& data, const Matrix3& transformation, const UnsignedInt id) {
CORRADE_ASSERT(data.vertexDataFlags() & Trade::DataFlag::Mutable,
void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transformTextureCoordinates2DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = data.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id);
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id);
CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index" << id, );
CORRADE_ASSERT(data.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2,
"MeshTools::transformTextureCoordinates2DInPlace(): expected" << VertexFormat::Vector2 << "texture coordinates but got" << data.attributeFormat(*textureCoordinateAttributeId), );
CORRADE_ASSERT(mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2,
"MeshTools::transformTextureCoordinates2DInPlace(): expected" << VertexFormat::Vector2 << "texture coordinates but got" << mesh.attributeFormat(*textureCoordinateAttributeId), );
/** @todo this needs a proper batch implementation */
for(Vector2& position: data.mutableAttribute<Vector2>(*textureCoordinateAttributeId))
for(Vector2& position: mesh.mutableAttribute<Vector2>(*textureCoordinateAttributeId))
position = transformation.transformPoint(position);
}

18
src/Magnum/MeshTools/Transform.h

@ -165,7 +165,7 @@ copy, you can also do an in-place transformation using @ref transform2DInPlace()
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const,
@ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& data, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 2D positions in a mesh data
@ -177,7 +177,7 @@ data ownership to the returned instance, if both vertex and index data is
owned, vertex data is mutable and the positions with index @p id are
@ref VertexFormat::Vector2.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(Trade::MeshData&& data, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 2D positions in a mesh data in-place
@ -194,7 +194,7 @@ packed types, the in-place operation requires the position type to be
@ref Trade::MeshData::attributeCount(MeshAttribute) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const
*/
MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& data, const Matrix3& transformation, UnsignedInt id = 0);
MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0);
/**
@brief Transform 3D positions, normals, tangents and bitangents in a mesh data
@ -223,7 +223,7 @@ copy, you can also do an in-place transformation using @ref transform3DInPlace()
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const,
@ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& data, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 3D positions, normals, tangenta and bitangents in a mesh data
@ -236,7 +236,7 @@ owned, vertex data is mutable, positions, normals and bitangents (if present)
are @ref VertexFormat::Vector3 and tangents (if present) either
@ref VertexFormat::Vector3 or @ref VertexFormat::Vector4.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(Trade::MeshData&& data, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 3D positions, normals, tangents and bitangents in a mesh data in-place
@ -258,7 +258,7 @@ than @p id, and indices (if any) are left untouched.
@ref Trade::MeshData::attributeCount(MeshAttribute) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const
*/
MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& data, const Matrix4& transformation, UnsignedInt id = 0);
MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0);
/**
@brief Transform 2D texture coordinates in a mesh data
@ -280,7 +280,7 @@ copy, you can also do an in-place transformation using
@ref Trade::MeshData::attributeCount(MeshAttribute) const,
@ref isVertexFormatImplementationSpecific()
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& data, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 2D texture coordinates in a mesh data
@ -292,7 +292,7 @@ data ownership to the returned instance, if both vertex and index data is
owned, vertex data is mutable and the coordinates with index @p id are
@ref VertexFormat::Vector2.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& data, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
/**
@brief Transform 2D texture coordinates in a mesh data in-place
@ -311,7 +311,7 @@ untouched.
@ref Trade::MeshData::attributeCount(MeshAttribute) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt) const
*/
MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& data, const Matrix3& transformation, UnsignedInt id = 0);
MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0);
}}

Loading…
Cancel
Save