Browse Source

Hiding MeshTools implementation classes from user altogether.

All classes moved to MeshTools::Implementation namespace and removed
from Doxygen output. They now all return tuples instead of custom
structures. Updated and improved documentation, removed references to
implementation classes.
pull/279/head
Vladimír Vondruš 14 years ago
parent
commit
91c2b5e389
  1. 38
      src/MeshTools/Clean.h
  2. 102
      src/MeshTools/CompressIndices.h
  3. 138
      src/MeshTools/Interleave.h
  4. 36
      src/MeshTools/Subdivide.h
  5. 43
      src/MeshTools/Test/CompressIndicesTest.cpp
  6. 29
      src/MeshTools/Test/InterleaveTest.cpp
  7. 2
      src/MeshTools/Test/TipsifyTest.cpp
  8. 6
      src/MeshTools/Tipsify.cpp
  9. 33
      src/MeshTools/Tipsify.h

38
src/MeshTools/Clean.h

@ -16,7 +16,7 @@
*/ */
/** @file /** @file
* @brief Class Magnum::MeshTools::Clean, function Magnum::MeshTools::clean() * @brief Function Magnum::MeshTools::clean()
*/ */
#include <unordered_map> #include <unordered_map>
@ -27,25 +27,13 @@
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
/** #ifndef DOXYGEN_GENERATING_OUTPUT
@brief %Mesh cleaner implementation namespace Implementation {
See clean() for full documentation.
*/
template<class Vertex, size_t vertexSize = Vertex::Size> class Clean { template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
public: public:
/**
* @brief Constructor
*
* See clean() for full documentation.
*/
inline Clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {} inline Clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {}
/**
* @brief Functor
*
* See clean() for full documentation.
*/
void operator()(typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) { void operator()(typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
if(indices.empty()) return; if(indices.empty()) return;
@ -128,6 +116,9 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
std::vector<Vertex>& vertices; std::vector<Vertex>& vertices;
}; };
}
#endif
/** /**
@brief %Clean the mesh @brief %Clean the mesh
@tparam Vertex Vertex data type @tparam Vertex Vertex data type
@ -140,24 +131,9 @@ template<class Vertex, size_t vertexSize = Vertex::Size> class Clean {
melt together. melt together.
Removes duplicate vertices from the mesh. Removes duplicate vertices from the mesh.
This is convenience function supplementing direct usage of Clean class,
instead of
@code
MeshTools::Clean<T>(indices, vertices)(epsilon);
@endcode
you can just write
@code
MeshTools::clean(indices, vertices, epsilon);
@endcode
However, when you want to specify `vertexSize` template parameter, you have
to explicitly specify both of them:
@code
MeshTools::clean<T, 3>(indices, vertices, epsilon);
@endcode
*/ */
template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) { template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, typename Vertex::Type epsilon = TypeTraits<typename Vertex::Type>::epsilon()) {
Clean<Vertex, vertexSize>(indices, vertices)(epsilon); Implementation::Clean<Vertex, vertexSize>(indices, vertices)(epsilon);
} }
}} }}

102
src/MeshTools/CompressIndices.h

@ -16,7 +16,7 @@
*/ */
/** @file /** @file
* @brief Class Magnum::MeshTools::CompressIndices, function Magnum::MeshTools::compressIndices() * @brief Function Magnum::MeshTools::compressIndices()
*/ */
#include <cstring> #include <cstring>
@ -29,64 +29,33 @@
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
/** #ifndef DOXYGEN_GENERATING_OUTPUT
@brief Index compressor implementation namespace Implementation {
See compressIndices() for full documentation.
*/
class CompressIndices { class CompressIndices {
public: public:
/**
* @brief Compressed index array
*
* Size of the data buffer can be computed as follows:
* @code
* Result result;
* size_t size = result.indexCount*TypeInfo::sizeOf(result.indexType);
* @endcode
*/
struct Result {
size_t indexCount; /**< @brief Index count */
Type indexType; /**< @brief Index data type */
char* data; /**< @brief Data buffer */
};
/**
* @brief Constructor
*
* See compressIndices() for full documentation.
*/
CompressIndices(const std::vector<unsigned int>& indices): indices(indices) {} CompressIndices(const std::vector<unsigned int>& indices): indices(indices) {}
/** inline std::tuple<size_t, Type, char*> operator()() const {
* @brief Functor
*
* See compressIndices(const std::vector<unsigned int>&) for full
* documentation.
*/
inline Result operator()() const {
return SizeBasedCall<Compressor>(*std::max_element(indices.begin(), indices.end()))(indices); return SizeBasedCall<Compressor>(*std::max_element(indices.begin(), indices.end()))(indices);
} }
/**
* @brief Functor
*
* See compressIndices(IndexedMesh*, Buffer::Usage, const
* std::vector<unsigned int>&) for full documentation.
*/
void operator()(IndexedMesh* mesh, Buffer::Usage usage) const { void operator()(IndexedMesh* mesh, Buffer::Usage usage) const {
Result compressed = operator()(); size_t indexCount;
Type indexType;
char* data;
std::tie(indexCount, indexType, data) = operator()();
mesh->setIndexType(compressed.indexType); mesh->setIndexType(indexType);
mesh->setIndexCount(indices.size()); mesh->setIndexCount(indices.size());
mesh->indexBuffer()->setData(compressed.indexCount*TypeInfo::sizeOf(compressed.indexType), compressed.data, usage); mesh->indexBuffer()->setData(indexCount*TypeInfo::sizeOf(indexType), data, usage);
delete[] compressed.data; delete[] data;
} }
private: private:
struct Compressor { struct Compressor {
template<class IndexType> static Result run(const std::vector<unsigned int>& indices) { template<class IndexType> static std::tuple<size_t, Type, char*> run(const std::vector<unsigned int>& indices) {
/* Create smallest possible version of index buffer */ /* Create smallest possible version of index buffer */
char* buffer = new char[indices.size()*sizeof(IndexType)]; char* buffer = new char[indices.size()*sizeof(IndexType)];
for(size_t i = 0; i != indices.size(); ++i) { for(size_t i = 0; i != indices.size(); ++i) {
@ -94,35 +63,42 @@ class CompressIndices {
memcpy(buffer+i*sizeof(IndexType), reinterpret_cast<const char*>(&index), sizeof(IndexType)); memcpy(buffer+i*sizeof(IndexType), reinterpret_cast<const char*>(&index), sizeof(IndexType));
} }
return Result{indices.size(), TypeTraits<IndexType>::indexType(), buffer}; return std::make_tuple(indices.size(), TypeTraits<IndexType>::indexType(), buffer);
} }
}; };
const std::vector<unsigned int>& indices; const std::vector<unsigned int>& indices;
}; };
}
#endif
/** /**
@brief Compress vertex indices @brief Compress vertex indices
@param indices Index array @param indices Index array
@return Compressed index array. Deleting the buffer is user's responsibility. @return Index count, type and compressed index array. Deleting the array is
user responsibility.
This function takes index array and outputs them compressed to smallest This function takes index array and outputs them compressed to smallest
possible size. For example when your indices have maximum number 463, it's possible size. For example when your indices have maximum number 463, it's
wasteful to store them in array of `unsigned int`s, array of wasteful to store them in array of `unsigned int`s, array of `unsigned short`s
`unsigned short`s is sufficient. is sufficient. Size of the buffer can be computed from index count and type,
as shown below. Example usage:
This is convenience function supplementing direct usage of CompressIndices
class, instead of
@code @code
MeshTools::CompressIndices{indices}(); size_t indexCount;
@endcode Type indexType;
you can just write char* data;
@code std::tie(indexCount, indexType, data) = MeshTools::compressIndices(indices);
MeshTools::compressIndices(indices); size_t dataSize = indexCount*TypeInfo::sizeOf(indexType);
// ...
delete[] data;
@endcode @endcode
See also compressIndices(IndexedMesh*, Buffer::Usage, const std::vector<unsigned int>&),
which writes the compressed data directly into index buffer of given mesh.
*/ */
inline CompressIndices::Result compressIndices(const std::vector<unsigned int>& indices) { inline std::tuple<size_t, Type, char*> compressIndices(const std::vector<unsigned int>& indices) {
return CompressIndices{indices}(); return Implementation::CompressIndices{indices}();
} }
/** /**
@ -134,19 +110,9 @@ inline CompressIndices::Result compressIndices(const std::vector<unsigned int>&
The same as compressIndices(const std::vector<unsigned int>&), but this The same as compressIndices(const std::vector<unsigned int>&), but this
function writes the output to mesh's index buffer and updates index count and function writes the output to mesh's index buffer and updates index count and
type in the mesh accordingly. type in the mesh accordingly.
This is convenience function supplementing direct usage of CompressIndices
class, instead of
@code
MeshTools::CompressIndices{indices}(mesh, usage);
@endcode
you can just write
@code
MeshTools::compressIndices(mesh, usage, indices);
@endcode
*/ */
inline void compressIndices(IndexedMesh* mesh, Buffer::Usage usage, const std::vector<unsigned int>& indices) { inline void compressIndices(IndexedMesh* mesh, Buffer::Usage usage, const std::vector<unsigned int>& indices) {
return CompressIndices{indices}(mesh, usage); return Implementation::CompressIndices{indices}(mesh, usage);
} }
}} }}

138
src/MeshTools/Interleave.h

@ -16,110 +16,77 @@
*/ */
/** @file /** @file
* @brief Class Magnum::MeshTools::Interleave, function Magnum::MeshTools::interleave() * @brief Function Magnum::MeshTools::interleave()
*/ */
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <limits> #include <limits>
#include <tuple>
#include "Mesh.h" #include "Mesh.h"
#include "Buffer.h" #include "Buffer.h"
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
/** #ifndef DOXYGEN_GENERATING_OUTPUT
@brief Vertex attribute interleaver implementation namespace Implementation {
See interleave() for full documentation.
*/
class Interleave { class Interleave {
public: public:
/** inline Interleave(): _attributeCount(0), _stride(0), _data(nullptr) {}
* @brief Interleaved attribute array
* template<class ...T> std::tuple<size_t, size_t, char*> operator()(const std::vector<T>&... attributes) {
* Size of the data buffer can be computed as follows:
* @code
* Result result;
* size_t size = result.attributeCount*result.stride;
* @endcode
*/
struct Result {
size_t attributeCount; /**< @brief Attribute count */
size_t stride; /**< @brief Distance between two attributes in resulting array */
char* data; /**< @brief Data buffer */
};
/** @brief Constructor */
#ifndef DOXYGEN_GENERATING_OUTPUT
inline Interleave(): result{0, 0, 0} {}
#else
inline Interleave() {}
#endif
/**
* @brief Functor
*
* See interleave(const std::vector<T>&...) for full documentation.
*/
template<class ...T> Result operator()(const std::vector<T>&... attributes) {
/* Compute buffer size and stride */ /* Compute buffer size and stride */
result.attributeCount = attributeCount(attributes...); _attributeCount = attributeCount(attributes...);
if(result.attributeCount) { if(_attributeCount) {
result.stride = stride(attributes...); _stride = stride(attributes...);
/* Create output buffer */ /* Create output buffer */
result.data = new char[result.attributeCount*result.stride]; _data = new char[_attributeCount*_stride];
/* Save the data */ /* Save the data */
write(result.data, attributes...); write(_data, attributes...);
} }
return result; return std::make_tuple(_attributeCount, _stride, _data);
} }
/**
* @brief Functor
*
* See interleave(Mesh*, Buffer*, Buffer::Usage, const std::vector<T>&...) for full documentation.
*/
template<class ...T> void operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<T>&... attributes) { template<class ...T> void operator()(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<T>&... attributes) {
if(!mesh->isInterleaved(buffer)) { if(!mesh->isInterleaved(buffer)) {
Corrade::Utility::Error() << "MeshTools::Interleave: the buffer is not interleaved, nothing done"; Corrade::Utility::Error() << "MeshTools::interleave(): the buffer is not interleaved, nothing done";
assert(0); assert(0);
return; return;
} }
operator()(attributes...); operator()(attributes...);
mesh->setVertexCount(result.attributeCount); mesh->setVertexCount(_attributeCount);
buffer->setData(result.attributeCount*result.stride, result.data, usage); buffer->setData(_attributeCount*_stride, _data, usage);
delete[] result.data; delete[] _data;
} }
/** @brief Count of passed attributes */
template<class T, class ...U> inline static size_t attributeCount(const std::vector<T>& first, const std::vector<U>&... next) { template<class T, class ...U> inline static size_t attributeCount(const std::vector<T>& first, const std::vector<U>&... next) {
size_t count = attributeCount(next...); size_t count = attributeCount(next...);
if(sizeof...(next) != 0 && count != first.size()) { if(sizeof...(next) != 0 && count != first.size()) {
Corrade::Utility::Error() << "MeshTools::Interleave: attribute arrays don't have the same length, nothing done."; Corrade::Utility::Error() << "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.";
assert(0); assert(0);
return 0; return 0;
} }
return first.size(); return first.size();
} }
/** @brief Distance between two attributes in resulting array */
template<class T, class ...U> inline static size_t stride(const std::vector<T>& first, const std::vector<U>&... next) { template<class T, class ...U> inline static size_t stride(const std::vector<T>& first, const std::vector<U>&... next) {
return sizeof(T) + stride(next...); return sizeof(T) + stride(next...);
} }
private: private:
template<class T, class ...U> void write(char* startingOffset, const std::vector<T>& first, const std::vector<U>&... next) const { template<class T, class ...U> void write(char* startingOffset, const std::vector<T>& first, const std::vector<U>&... next) {
/* Copy the data to the buffer */ /* Copy the data to the buffer */
for(size_t i = 0; i != result.attributeCount; ++i) for(size_t i = 0; i != _attributeCount; ++i)
memcpy(startingOffset+i*result.stride, reinterpret_cast<const char*>(&first[i]), sizeof(T)); memcpy(startingOffset+i*_stride, reinterpret_cast<const char*>(&first[i]), sizeof(T));
write(startingOffset+sizeof(T), next...); write(startingOffset+sizeof(T), next...);
} }
@ -127,35 +94,44 @@ class Interleave {
/* Terminator functions for recursive calls */ /* Terminator functions for recursive calls */
inline static size_t attributeCount() { return 0; } inline static size_t attributeCount() { return 0; }
inline static size_t stride() { return 0; } inline static size_t stride() { return 0; }
inline void write(char*) const {} inline void write(char*) {}
Result result; size_t _attributeCount;
size_t _stride;
char* _data;
}; };
}
#endif
/** /**
@brief %Interleave vertex attributes @brief %Interleave vertex attributes
@param attributes Attribute arrays @param attributes Attribute arrays
@return Interleaved attribute array. Deleting the buffer is user's @return Attribute count, stride and interleaved attribute array. Deleting the
responsibility. array is user responsibility.
This function takes two or more attribute arrays and interleaves them, so data
for each attribute are in continuous place in memory.
@attention Each vector should have the same size, if not, resulting array has This function takes two or more attribute arrays and returns them interleaved,
zero length. so data for each attribute are in continuous place in memory. Size of the data
buffer can be computed from attribute count and stride, as shown below. Example
This is convenience function supplementing direct usage of Interleave class, usage:
instead of
@code @code
MeshTools::Interleave()(attributes...); size_t attributeCount;
@endcode size_t stride;
you can just write char* data;
@code std::tie(attributeCount, stride, data) = MeshTools::interleave(attributes);
MeshTools::interleave(attributes...); size_t dataSize = attributeCount*stride;
// ...
delete[] data;
@endcode @endcode
See also interleave(Mesh*, Buffer*, Buffer::Usage, const std::vector<T>&...),
which writes the interleaved array directly into buffer of given mesh.
@attention Each vector should have the same size, if not, resulting array has
zero length.
*/ */
template<class ...T> inline Interleave::Result interleave(const std::vector<T>&... attributes) { template<class ...T> inline std::tuple<size_t, size_t, char*> interleave(const std::vector<T>&... attributes) {
return Interleave()(attributes...); return Implementation::Interleave()(attributes...);
} }
/** /**
@ -170,21 +146,11 @@ the output to given array buffer and updates vertex count in the mesh
accordingly. accordingly.
@attention The buffer must be set as interleaved (see Mesh::addBuffer()), @attention The buffer must be set as interleaved (see Mesh::addBuffer()),
otherwise this function does nothing. Binding the attributes to shader is otherwise this function does nothing. Binding the attributes to shader is
left to user. left to user.
This is convenience function supplementing direct usage of Interleave class,
instead of
@code
MeshTools::Interleave()(mesh, buffer, usage, attributes...);
@endcode
you can just write
@code
MeshTools::interleave(mesh, buffer, usage, attributes...);
@endcode
*/ */
template<class ...T> inline void interleave(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<T>&... attributes) { template<class ...T> inline void interleave(Mesh* mesh, Buffer* buffer, Buffer::Usage usage, const std::vector<T>&... attributes) {
return Interleave()(mesh, buffer, usage, attributes...); return Implementation::Interleave()(mesh, buffer, usage, attributes...);
} }
}} }}

36
src/MeshTools/Subdivide.h

@ -16,32 +16,21 @@
*/ */
/** @file /** @file
* @brief Class Magnum::MeshTools::Subdivide, function Magnum::MeshTools::subdivide() * @brief Function Magnum::MeshTools::subdivide()
*/ */
#include <vector> #include <vector>
#include "Utility/Debug.h"
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
/** #ifndef DOXYGEN_GENERATING_OUTPUT
@brief %Mesh subdivisor implementation namespace Implementation {
See subdivide() for full documentation.
*/
template<class Vertex, class Interpolator> class Subdivide { template<class Vertex, class Interpolator> class Subdivide {
public: public:
/**
* @brief Constructor
*
* See subdivide() for full documentation.
*/
inline Subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {} inline Subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices): indices(indices), vertices(vertices) {}
/**
* @brief Functor
*
* See subdivide() for full documentation.
*/
void operator()(Interpolator interpolator) { void operator()(Interpolator interpolator) {
size_t indexCount = indices.size(); size_t indexCount = indices.size();
indices.reserve(indices.size()*4); indices.reserve(indices.size()*4);
@ -90,9 +79,12 @@ template<class Vertex, class Interpolator> class Subdivide {
} }
}; };
}
#endif
/** /**
@brief %Subdivide the mesh @brief %Subdivide the mesh
@tparam Vertex Vertex data type (the same as in MeshBuilder) @tparam Vertex Vertex data type
@tparam Interpolator See `interpolator` function parameter @tparam Interpolator See `interpolator` function parameter
@param indices Index array to operate on @param indices Index array to operate on
@param vertices Vertex array to operate on @param vertices Vertex array to operate on
@ -101,19 +93,9 @@ template<class Vertex, class Interpolator> class Subdivide {
Goes through all triangle faces and subdivides them into four new. Cleaning Goes through all triangle faces and subdivides them into four new. Cleaning
duplicate vertices in the mesh is up to user. duplicate vertices in the mesh is up to user.
This is convenience function supplementing direct usage of Subdivide class,
instead of
@code
MeshTools::Subdivide<T, Interpolator>(indices, vertices)(interpolator);
@endcode
you can just write
@code
MeshTools::subdivide(indices, vertices, interpolator);
@endcode
*/ */
template<class Vertex, class Interpolator> inline void subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, Interpolator interpolator) { template<class Vertex, class Interpolator> inline void subdivide(std::vector<unsigned int>& indices, std::vector<Vertex>& vertices, Interpolator interpolator) {
Subdivide<Vertex, Interpolator>(indices, vertices)(interpolator); Implementation::Subdivide<Vertex, Interpolator>(indices, vertices)(interpolator);
} }
}} }}

43
src/MeshTools/Test/CompressIndicesTest.cpp

@ -28,62 +28,71 @@ using namespace Corrade::Utility;
namespace Magnum { namespace MeshTools { namespace Test { namespace Magnum { namespace MeshTools { namespace Test {
void CompressIndicesTest::compressChar() { void CompressIndicesTest::compressChar() {
CompressIndices::Result result = MeshTools::compressIndices( size_t indexCount;
Type indexType;
char* data;
tie(indexCount, indexType, data) = MeshTools::compressIndices(
vector<unsigned int>{1, 2, 3, 0, 4}); vector<unsigned int>{1, 2, 3, 0, 4});
QVERIFY(result.indexCount == 5); QVERIFY(indexCount == 5);
QVERIFY(result.indexType == Type::UnsignedByte); QVERIFY(indexType == Type::UnsignedByte);
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == QVERIFY((vector<char>(data, data+indexCount*TypeInfo::sizeOf(indexType)) ==
vector<char>{ 0x01, 0x02, 0x03, 0x00, 0x04 })); vector<char>{ 0x01, 0x02, 0x03, 0x00, 0x04 }));
delete[] result.data; delete[] data;
} }
void CompressIndicesTest::compressShort() { void CompressIndicesTest::compressShort() {
CompressIndices::Result result = MeshTools::compressIndices( size_t indexCount;
Type indexType;
char* data;
tie(indexCount, indexType, data) = MeshTools::compressIndices(
vector<unsigned int>{1, 256, 0, 5}); vector<unsigned int>{1, 256, 0, 5});
QVERIFY(result.indexCount == 4); QVERIFY(indexCount == 4);
QVERIFY(result.indexType == Type::UnsignedShort); QVERIFY(indexType == Type::UnsignedShort);
if(!Endianness::isBigEndian()) { if(!Endianness::isBigEndian()) {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == QVERIFY((vector<char>(data, data+indexCount*TypeInfo::sizeOf(indexType)) ==
vector<char>{ 0x01, 0x00, vector<char>{ 0x01, 0x00,
0x00, 0x01, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
0x05, 0x00 })); 0x05, 0x00 }));
} else { } else {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == QVERIFY((vector<char>(data, data+indexCount*TypeInfo::sizeOf(indexType)) ==
vector<char>{ 0x00, 0x01, vector<char>{ 0x00, 0x01,
0x01, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x05 })); 0x00, 0x05 }));
} }
delete[] result.data; delete[] data;
} }
void CompressIndicesTest::compressInt() { void CompressIndicesTest::compressInt() {
CompressIndices::Result result = MeshTools::compressIndices( size_t indexCount;
Type indexType;
char* data;
tie(indexCount, indexType, data) = MeshTools::compressIndices(
vector<unsigned int>{65536, 3, 2}); vector<unsigned int>{65536, 3, 2});
QVERIFY(result.indexCount == 3); QVERIFY(indexCount == 3);
QVERIFY(result.indexType == Type::UnsignedInt); QVERIFY(indexType == Type::UnsignedInt);
if(!Endianness::isBigEndian()) { if(!Endianness::isBigEndian()) {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == QVERIFY((vector<char>(data, data+indexCount*TypeInfo::sizeOf(indexType)) ==
vector<char>{ 0x00, 0x00, 0x01, 0x00, vector<char>{ 0x00, 0x00, 0x01, 0x00,
0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00 0x02, 0x00, 0x00, 0x00
})); }));
} else { } else {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == QVERIFY((vector<char>(data, data+indexCount*TypeInfo::sizeOf(indexType)) ==
vector<char>{ 0x00, 0x01, 0x00, 0x00, vector<char>{ 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x02 0x00, 0x00, 0x00, 0x02
})); }));
} }
delete[] result.data; delete[] data;
} }
}}} }}}

29
src/MeshTools/Test/InterleaveTest.cpp

@ -36,44 +36,47 @@ namespace Magnum { namespace MeshTools { namespace Test {
void InterleaveTest::attributeCount() { void InterleaveTest::attributeCount() {
stringstream ss; stringstream ss;
Error::setOutput(&ss); Error::setOutput(&ss);
QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2}, QCOMPARE((Implementation::Interleave::attributeCount(vector<char>{0, 1, 2},
vector<char>{0, 1, 2, 3, 4, 5})), size_t(0)); vector<char>{0, 1, 2, 3, 4, 5})), size_t(0));
QVERIFY(ss.str() == "MeshTools::Interleave: attribute arrays don't have the same length, nothing done.\n"); QVERIFY(ss.str() == "MeshTools::interleave(): attribute arrays don't have the same length, nothing done.\n");
QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2}, QCOMPARE((Implementation::Interleave::attributeCount(vector<char>{0, 1, 2},
vector<char>{3, 4, 5})), size_t(3)); vector<char>{3, 4, 5})), size_t(3));
} }
void InterleaveTest::stride() { void InterleaveTest::stride() {
QCOMPARE(Interleave::stride(vector<char>()), size_t(1)); QCOMPARE(Implementation::Interleave::stride(vector<char>()), size_t(1));
QCOMPARE(Interleave::stride(vector<int>()), size_t(4)); QCOMPARE(Implementation::Interleave::stride(vector<int>()), size_t(4));
QCOMPARE((Interleave::stride(vector<char>(), vector<int>())), size_t(5)); QCOMPARE((Implementation::Interleave::stride(vector<char>(), vector<int>())), size_t(5));
} }
void InterleaveTest::write() { void InterleaveTest::write() {
Interleave::Result data = MeshTools::interleave( size_t attributeCount;
size_t stride;
char* data;
tie(attributeCount, stride, data) = MeshTools::interleave(
vector<char>{0, 1, 2}, vector<char>{0, 1, 2},
vector<int>{3, 4, 5}, vector<int>{3, 4, 5},
vector<short>{6, 7, 8}); vector<short>{6, 7, 8});
QCOMPARE(data.attributeCount, size_t(3)); QCOMPARE(attributeCount, size_t(3));
QCOMPARE(data.stride, size_t(7)); QCOMPARE(stride, size_t(7));
size_t size = data.attributeCount*data.stride; size_t size = attributeCount*stride;
if(!Endianness::isBigEndian()) { if(!Endianness::isBigEndian()) {
QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{ QVERIFY((vector<char>(data, data+size) == vector<char>{
0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00,
0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00,
0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00 0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00
})); }));
} else { } else {
QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{ QVERIFY((vector<char>(data, data+size) == vector<char>{
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07,
0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08
})); }));
} }
delete[] data.data; delete[] data;
} }
}}} }}}

2
src/MeshTools/Test/TipsifyTest.cpp

@ -67,7 +67,7 @@ TipsifyTest::TipsifyTest(QObject* parent): QObject(parent), indices{
void TipsifyTest::buildAdjacency() { void TipsifyTest::buildAdjacency() {
vector<unsigned int> liveTriangleCount, neighborOffset, neighbors; vector<unsigned int> liveTriangleCount, neighborOffset, neighbors;
Tipsify(indices, vertexCount).buildAdjacency(liveTriangleCount, neighborOffset, neighbors); Implementation::Tipsify(indices, vertexCount).buildAdjacency(liveTriangleCount, neighborOffset, neighbors);
QVERIFY((liveTriangleCount == vector<unsigned int>{ QVERIFY((liveTriangleCount == vector<unsigned int>{
1, 3, 3, 2, 1, 3, 3, 2,

6
src/MeshTools/Tipsify.cpp

@ -17,7 +17,8 @@
#include <stack> #include <stack>
namespace Magnum { namespace MeshTools { #ifndef DOXYGEN_GENERATING_OUTPUT
namespace Magnum { namespace MeshTools { namespace Implementation {
void Tipsify::operator()(size_t cacheSize) { void Tipsify::operator()(size_t cacheSize) {
/* Neighboring triangles for each vertex, per-vertex live triangle count */ /* Neighboring triangles for each vertex, per-vertex live triangle count */
@ -145,4 +146,5 @@ void Tipsify::buildAdjacency(std::vector<unsigned int>& liveTriangleCount, std::
neighbors[neighborOffset[indices[i]+1]++] = i/3; neighbors[neighborOffset[indices[i]+1]++] = i/3;
} }
}} }}}
#endif

33
src/MeshTools/Tipsify.h

@ -16,7 +16,7 @@
*/ */
/** @file /** @file
* @brief Class Magnum::MeshTools::Tipsify, function Magnum::MeshTools::tipsify() * @brief Function Magnum::MeshTools::tipsify()
*/ */
#include <cstddef> #include <cstddef>
@ -26,25 +26,13 @@
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
/** #ifndef DOXYGEN_GENERATING_OUTPUT
@brief %Mesh tipsifier implementation namespace Implementation {
See tipsify() for full documentation.
*/
class MESHTOOLS_EXPORT Tipsify { class MESHTOOLS_EXPORT Tipsify {
public: public:
/**
* @brief Constructor
*
* See tipsify() for full documentation.
*/
inline Tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount): indices(indices), vertexCount(vertexCount) {} inline Tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount): indices(indices), vertexCount(vertexCount) {}
/**
* @brief Functor
*
* See tipsify() for full documentation.
*/
void operator()(size_t cacheSize); void operator()(size_t cacheSize);
/** /**
@ -60,6 +48,9 @@ class MESHTOOLS_EXPORT Tipsify {
const unsigned int vertexCount; const unsigned int vertexCount;
}; };
}
#endif
/** /**
@brief %Tipsify the mesh @brief %Tipsify the mesh
@param indices Indices array to operate on @param indices Indices array to operate on
@ -71,19 +62,9 @@ array for beter usage of post-transform vertex cache. Algorithm used:
*Pedro V. Sander, Diego Nehab, and Joshua Barczak - Fast Triangle Reordering *Pedro V. Sander, Diego Nehab, and Joshua Barczak - Fast Triangle Reordering
for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007, for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007,
http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/index.php*. http://gfx.cs.princeton.edu/pubs/Sander_2007_%3ETR/index.php*.
This is convenience function supplementing direct usage of Tipsify class,
instead of
@code
MeshTools::Tipsify(indices, vertexCount)(cacheSize);
@endcode
you can just write
@code
MeshTools::tipsify(indices, vertexCount, cacheSize);
@endcode
*/ */
inline void tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount, size_t cacheSize) { inline void tipsify(std::vector<unsigned int>& indices, unsigned int vertexCount, size_t cacheSize) {
Tipsify(indices, vertexCount)(cacheSize); Implementation::Tipsify(indices, vertexCount)(cacheSize);
} }
}} }}

Loading…
Cancel
Save