Browse Source

MeshTools: tool for compressing index array.

The same functionality which is buried inside MeshBuilder, but properly
tested and more usable.
vectorfields
Vladimír Vondruš 14 years ago
parent
commit
bca691f2b7
  1. 154
      src/MeshTools/CompressIndices.h
  2. 2
      src/MeshTools/Test/CMakeLists.txt
  3. 89
      src/MeshTools/Test/CompressIndicesTest.cpp
  4. 33
      src/MeshTools/Test/CompressIndicesTest.h

154
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š <mosra@centrum.cz>
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 <cstring>
#include <vector>
#include <algorithm>
#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<unsigned int>& indices): indices(indices) {}
/**
* @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);
}
/**
* @brief Functor
*
* See compressIndices(IndexedMesh*, Buffer::Usage, const
* std::vector<unsigned int>&) 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<class IndexType> static Result run(const std::vector<unsigned int>& 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<const char*>(&index), sizeof(IndexType));
}
return Result{indices.size(), TypeTraits<IndexType>::glType(), buffer};
}
};
const std::vector<unsigned int>& 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 <tt>unsigned int</tt>s, array of
<tt>unsigned short</tt>s 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<unsigned int>& 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<unsigned int>&), 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<unsigned int>& indices) {
return CompressIndices{indices}(mesh, usage);
}
}}
#endif

2
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})

89
src/MeshTools/Test/CompressIndicesTest.cpp

@ -0,0 +1,89 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
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 <QtTest/QTest>
#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<unsigned int>{1, 2, 3, 0, 4});
QVERIFY(result.indexCount == 5);
QVERIFY(result.indexType == Type::UnsignedByte);
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) ==
vector<char>{ 0x01, 0x02, 0x03, 0x00, 0x04 }));
delete[] result.data;
}
void CompressIndicesTest::compressShort() {
CompressIndices::Result result = MeshTools::compressIndices(
vector<unsigned int>{1, 256, 0, 5});
QVERIFY(result.indexCount == 4);
QVERIFY(result.indexType == Type::UnsignedShort);
if(!Endianness::isBigEndian()) {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) ==
vector<char>{ 0x01, 0x00,
0x00, 0x01,
0x00, 0x00,
0x05, 0x00 }));
} else {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) ==
vector<char>{ 0x00, 0x01,
0x01, 0x00,
0x00, 0x00,
0x00, 0x05 }));
}
delete[] result.data;
}
void CompressIndicesTest::compressInt() {
CompressIndices::Result result = MeshTools::compressIndices(
vector<unsigned int>{65536, 3, 2});
QVERIFY(result.indexCount == 3);
QVERIFY(result.indexType == Type::UnsignedInt);
if(!Endianness::isBigEndian()) {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) ==
vector<char>{ 0x00, 0x00, 0x01, 0x00,
0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00
}));
} else {
QVERIFY((vector<char>(result.data, result.data+result.indexCount*TypeInfo::sizeOf(result.indexType)) ==
vector<char>{ 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x02
}));
}
delete[] result.data;
}
}}}

33
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š <mosra@centrum.cz>
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 <QtCore/QObject>
namespace Magnum { namespace MeshTools { namespace Test {
class CompressIndicesTest: public QObject {
Q_OBJECT
private slots:
void compressChar();
void compressShort();
void compressInt();
};
}}}
#endif
Loading…
Cancel
Save