diff --git a/src/MeshTools/CompressIndices.h b/src/MeshTools/CompressIndices.h new file mode 100644 index 000000000..bf0987dac --- /dev/null +++ b/src/MeshTools/CompressIndices.h @@ -0,0 +1,154 @@ +#ifndef Magnum_MeshTools_CompressIndices_h +#define Magnum_MeshTools_CompressIndices_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +/** @file + * @brief Class Magnum::MeshTools::CompressIndices + */ + +#include +#include +#include + +#include "TypeTraits.h" +#include "SizeTraits.h" +#include "IndexedMesh.h" + +namespace Magnum { namespace MeshTools { + +/** +@brief Index compressor implementation + +See compressIndices() for full documentation. +*/ +class CompressIndices { + 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& indices): indices(indices) {} + + /** + * @brief Functor + * + * See compressIndices(const std::vector&) for full + * documentation. + */ + inline Result operator()() const { + return SizeBasedCall(*std::max_element(indices.begin(), indices.end()))(indices); + } + + /** + * @brief Functor + * + * See compressIndices(IndexedMesh*, Buffer::Usage, const + * std::vector&) for full documentation. + */ + void operator()(IndexedMesh* mesh, Buffer::Usage usage) const { + Result compressed = operator()(); + + mesh->setIndexType(compressed.indexType); + mesh->setIndexCount(indices.size()); + mesh->indexBuffer()->setData(compressed.indexCount*TypeInfo::sizeOf(compressed.indexType), compressed.data, usage); + + delete[] compressed.data; + } + + private: + struct Compressor { + template static Result run(const std::vector& indices) { + /* Create smallest possible version of index buffer */ + char* buffer = new char[indices.size()*sizeof(IndexType)]; + for(size_t i = 0; i != indices.size(); ++i) { + IndexType index = indices[i]; + memcpy(buffer+i*sizeof(IndexType), reinterpret_cast(&index), sizeof(IndexType)); + } + + return Result{indices.size(), TypeTraits::glType(), buffer}; + } + }; + + const std::vector& indices; +}; + +/** +@brief Compress vertex indices +@param indices Index array +@return Compressed index array. Deleting the buffer is user's responsibility. + +This function takes index array and outputs them compressed to smallest +possible size. For example when your indices have maximum number 463, it's +wasteful to store them in array of unsigned ints, array of +unsigned shorts is sufficient. + +This is convenience function supplementing direct usage of CompressIndices +class, instead of +@code +MeshTools::CompressIndices{indices}(); +@endcode +you can just write +@code +MeshTools::compressIndices(indices); +@endcode +*/ +inline CompressIndices::Result compressIndices(const std::vector& indices) { + return CompressIndices{indices}(); +} + +/** +@brief Compress vertex indices and write them to index buffer +@param indices Index array +@param mesh Output mesh +@param usage Index buffer usage + +The same as compressIndices(const std::vector&), but this +function writes the output to mesh's index buffer and updates index count and +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& indices) { + return CompressIndices{indices}(mesh, usage); +} + +}} + +#endif diff --git a/src/MeshTools/Test/CMakeLists.txt b/src/MeshTools/Test/CMakeLists.txt index 03197560e..c321eb021 100644 --- a/src/MeshTools/Test/CMakeLists.txt +++ b/src/MeshTools/Test/CMakeLists.txt @@ -1,4 +1,6 @@ corrade_add_test(CleanTest CleanTest.h CleanTest.cpp) +corrade_add_test(CompressIndicesTest CompressIndicesTest.h CompressIndicesTest.cpp) +target_link_libraries(CompressIndicesTest ${CORRADE_UTILITY_LIBRARY} ${MAGNUM_LIBRARY}) corrade_add_test(SubdivideTest SubdivideTest.h SubdivideTest.cpp) corrade_add_test(SubdivideCleanBenchmark SubdivideCleanBenchmark.h SubdivideCleanBenchmark.cpp) target_link_libraries(SubdivideCleanBenchmark ${MAGNUM_PRIMITIVES_LIBRARY}) diff --git a/src/MeshTools/Test/CompressIndicesTest.cpp b/src/MeshTools/Test/CompressIndicesTest.cpp new file mode 100644 index 000000000..f6b4a1631 --- /dev/null +++ b/src/MeshTools/Test/CompressIndicesTest.cpp @@ -0,0 +1,89 @@ +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include "CompressIndicesTest.h" + +#include + +#include "Utility/Endianness.h" +#include "MeshTools/CompressIndices.h" + +QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::CompressIndicesTest) + +using namespace std; +using namespace Corrade::Utility; + +namespace Magnum { namespace MeshTools { namespace Test { + +void CompressIndicesTest::compressChar() { + CompressIndices::Result result = MeshTools::compressIndices( + vector{1, 2, 3, 0, 4}); + + QVERIFY(result.indexCount == 5); + QVERIFY(result.indexType == Type::UnsignedByte); + QVERIFY((vector(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == + vector{ 0x01, 0x02, 0x03, 0x00, 0x04 })); + + delete[] result.data; +} + +void CompressIndicesTest::compressShort() { + CompressIndices::Result result = MeshTools::compressIndices( + vector{1, 256, 0, 5}); + + QVERIFY(result.indexCount == 4); + QVERIFY(result.indexType == Type::UnsignedShort); + if(!Endianness::isBigEndian()) { + QVERIFY((vector(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == + vector{ 0x01, 0x00, + 0x00, 0x01, + 0x00, 0x00, + 0x05, 0x00 })); + } else { + QVERIFY((vector(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == + vector{ 0x00, 0x01, + 0x01, 0x00, + 0x00, 0x00, + 0x00, 0x05 })); + } + + delete[] result.data; +} + +void CompressIndicesTest::compressInt() { + CompressIndices::Result result = MeshTools::compressIndices( + vector{65536, 3, 2}); + + QVERIFY(result.indexCount == 3); + QVERIFY(result.indexType == Type::UnsignedInt); + + if(!Endianness::isBigEndian()) { + QVERIFY((vector(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == + vector{ 0x00, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00 + })); + } else { + QVERIFY((vector(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) == + vector{ 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02 + })); + } + + delete[] result.data; +} + +}}} diff --git a/src/MeshTools/Test/CompressIndicesTest.h b/src/MeshTools/Test/CompressIndicesTest.h new file mode 100644 index 000000000..614748eac --- /dev/null +++ b/src/MeshTools/Test/CompressIndicesTest.h @@ -0,0 +1,33 @@ +#ifndef Magnum_MeshTools_Test_CompressIndicesTest_h +#define Magnum_MeshTools_Test_CompressIndicesTest_h +/* + Copyright © 2010, 2011, 2012 Vladimír Vondruš + + This file is part of Magnum. + + Magnum is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 3 + only, as published by the Free Software Foundation. + + Magnum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License version 3 for more details. +*/ + +#include + +namespace Magnum { namespace MeshTools { namespace Test { + +class CompressIndicesTest: public QObject { + Q_OBJECT + + private slots: + void compressChar(); + void compressShort(); + void compressInt(); +}; + +}}} + +#endif