Browse Source

Splitting tools from MeshBuilderBenchmark to MeshTools.

Moved unit tests and benchmarks accordingly.
vectorfields
Vladimír Vondruš 15 years ago
parent
commit
37afb7bffe
  1. 1
      src/CMakeLists.txt
  2. 142
      src/MeshBuilder.h
  3. 157
      src/MeshTools/Clean.h
  4. 102
      src/MeshTools/Subdivide.h
  5. 4
      src/MeshTools/Test/CMakeLists.txt
  6. 44
      src/MeshTools/Test/CleanTest.cpp
  7. 48
      src/MeshTools/Test/CleanTest.h
  8. 78
      src/MeshTools/Test/SubdivideCleanBenchmark.cpp
  9. 11
      src/MeshTools/Test/SubdivideCleanBenchmark.h
  10. 51
      src/MeshTools/Test/SubdivideTest.cpp
  11. 50
      src/MeshTools/Test/SubdivideTest.h
  12. 2
      src/Test/CMakeLists.txt
  13. 77
      src/Test/MeshBuilderBenchmark.cpp
  14. 47
      src/Test/MeshBuilderTest.cpp
  15. 22
      src/Test/MeshBuilderTest.h

1
src/CMakeLists.txt

@ -3,6 +3,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -std=c++0x")
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CORRADE_INCLUDE_DIR})
add_subdirectory(Math)
add_subdirectory(MeshTools)
add_subdirectory(Primitives)
set(Magnum_SRCS

142
src/MeshBuilder.h

@ -30,18 +30,25 @@
namespace Magnum {
namespace MeshTools {
template<class Vertex> class AbstractTool;
}
/**
@brief Mesh builder
@tparam Vertex Vertex data
Class for building meshes with triangle primitive from scratch or from
prefabricated data and modifying them (adding/removing faces, cleaning duplicate
vertices etc.).
prefabricated data and modifying them using MeshBuilder alone or tools from
MeshTools namespace.
@todo Make it more generic for meshes with texture coordinates etc.
*/
template<class Vertex> class MeshBuilder {
friend class MeshTools::AbstractTool<Vertex>;
public:
/**
* @brief Destructor
*
@ -112,121 +119,6 @@ template<class Vertex> class MeshBuilder {
_indices.push_back(third);
}
/**
* @brief Subdivide mesh
* @param interpolator Functor or function pointer which interpolates
* two adjacent vertices: <tt>Vertex interpolator(Vertex a, Vertex
* b)</tt>
*
* Goes through all triangle faces and subdivides them in four new.
* Cleaning the mesh is up to user.
*/
template<class Interpolator> void subdivide(Interpolator interpolator) {
size_t indexCount = _indices.size();
_indices.reserve(_indices.size()*4);
/* Subdivide each face to four new */
for(size_t i = 0; i != indexCount; i += 3) {
/* Interpolate each side */
unsigned int newVertices[3];
for(int j = 0; j != 3; ++j)
newVertices[j] = addVertex(interpolator(_vertices[_indices[i+j]], _vertices[_indices[i+(j+1)%3]]));
/*
* Add three new faces (0, 1, 3) and update original (2)
*
* orig 0
* / \
* / 0 \
* / \
* new 0 ----- new 2
* / \ / \
* / 1 \ 2 / 3 \
* / \ / \
* orig 1 ----- new 1 ---- orig 2
*/
addFace(_indices[i], newVertices[0], newVertices[2]);
addFace(newVertices[0], _indices[i+1], newVertices[1]);
addFace(newVertices[2], newVertices[1], _indices[i+2]);
for(size_t j = 0; j != 3; ++j)
_indices[i+j] = newVertices[j];
}
}
/**
* @brief Clean the mesh
* @param epsilon Epsilon value, vertices nearer than this
* distance will be melt together.
*
* Removes duplicate vertices from the mesh. With template parameter
* @c vertexSize you can specify how many initial vertex fields are
* important (for example, when dealing with perspective in 3D space,
* only first three fields of otherwise 4D vertex are important).
*/
template<size_t vertexSize = Vertex::Size> void cleanMesh(typename Vertex::Type epsilon = EPSILON) {
if(_indices.empty()) return;
/* Get mesh bounds */
Vertex min, max;
for(size_t i = 0; i != Vertex::Size; ++i) {
min[i] = std::numeric_limits<typename Vertex::Type>::max();
max[i] = std::numeric_limits<typename Vertex::Type>::min();
}
for(auto it = _vertices.cbegin(); it != _vertices.cend(); ++it)
for(size_t i = 0; i != vertexSize; ++i)
if((*it)[i] < min[i])
min[i] = (*it)[i];
else if((*it)[i] > max[i])
max[i] = (*it)[i];
/* Make epsilon so large that size_t can index all vertices inside
mesh bounds. */
Vertex size = max-min;
for(size_t i = 0; i != Vertex::Size; ++i)
if(static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max()) > epsilon)
epsilon = static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max());
/* First go with original vertex coordinates, then move them by
epsilon/2 in each direction. */
Vertex moved;
for(size_t moving = 0; moving <= vertexSize; ++moving) {
/* Under each index is pointer to face which contains given vertex
and index of vertex in the face. */
std::unordered_map<Math::Vector<size_t, vertexSize>, HashedVertex, IndexHash<vertexSize>> table;
/* Reserve space for all vertices */
table.reserve(_vertices.size());
/* Go through all faces' vertices */
for(auto it = _indices.begin(); it != _indices.end(); ++it) {
/* Index of a vertex in vertexSize-dimensional table */
size_t index[vertexSize];
for(size_t ii = 0; ii != vertexSize; ++ii)
index[ii] = (_vertices[*it][ii]+moved[ii]-min[ii])/epsilon;
/* Try inserting the vertex into table, if it already
exists, change vertex pointer of the face to already
existing vertex */
HashedVertex v(*it, table.size());
auto result = table.insert(std::pair<Math::Vector<size_t, vertexSize>, HashedVertex>(index, v));
*it = result.first->second.newIndex;
}
/* Shrink vertices array */
std::vector<Vertex> vertices(table.size());
for(auto it = table.cbegin(); it != table.cend(); ++it)
vertices[it->second.newIndex] = _vertices[it->second.oldIndex];
std::swap(vertices, _vertices);
/* Move vertex coordinates by epsilon/2 in next direction */
if(moving != Vertex::Size) {
moved = Vertex();
moved[moving] = epsilon/2;
}
}
}
/**
* @brief Build indexed mesh and fill existing buffers with it
* @param mesh Mesh. The mesh primitive is set to
@ -267,22 +159,6 @@ template<class Vertex> class MeshBuilder {
std::vector<unsigned int> _indices;
std::vector<Vertex> _vertices;
template<size_t vertexSize> class IndexHash {
public:
inline size_t operator()(const Math::Vector<size_t, vertexSize>& data) const {
size_t a = 0;
for(size_t i = 0; i != vertexSize; ++i)
a ^= data[i];
return a;
}
};
struct HashedVertex {
unsigned int oldIndex, newIndex;
HashedVertex(unsigned int oldIndex, unsigned int newIndex): oldIndex(oldIndex), newIndex(newIndex) {}
};
struct IndexBuilder {
template<class IndexType> static void run(IndexedMesh* mesh, const std::vector<unsigned int>& _indices, Buffer::Usage indexBufferUsage) {
/* Compress face array to index array. Using

157
src/MeshTools/Clean.h

@ -0,0 +1,157 @@
#ifndef Magnum_MeshTools_Clean_h
#define Magnum_MeshTools_Clean_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::Clean
*/
#include "AbstractTool.h"
namespace Magnum { namespace MeshTools {
/**
@brief %Mesh cleaner implementation
See clean() for full documentation.
*/
template<class Vertex, size_t vertexSize = Vertex::Size> class Clean: public AbstractTool<Vertex> {
public:
/** @copydoc AbstractTool::AbstractTool() */
inline Clean(MeshBuilder<Vertex>& builder): AbstractTool<Vertex>(builder) {}
/**
* @brief Functor
*
* See clean() for full documentation.
*/
void run(typename Vertex::Type epsilon = EPSILON) {
if(this->indices.empty()) return;
/* Get mesh bounds */
Vertex min, max;
for(size_t i = 0; i != Vertex::Size; ++i) {
min[i] = std::numeric_limits<typename Vertex::Type>::max();
max[i] = std::numeric_limits<typename Vertex::Type>::min();
}
for(auto it = this->vertices.cbegin(); it != this->vertices.cend(); ++it)
for(size_t i = 0; i != vertexSize; ++i)
if((*it)[i] < min[i])
min[i] = (*it)[i];
else if((*it)[i] > max[i])
max[i] = (*it)[i];
/* Make epsilon so large that size_t can index all vertices inside
mesh bounds. */
Vertex size = max-min;
for(size_t i = 0; i != Vertex::Size; ++i)
if(static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max()) > epsilon)
epsilon = static_cast<typename Vertex::Type>(size[i]/std::numeric_limits<size_t>::max());
/* First go with original vertex coordinates, then move them by
epsilon/2 in each direction. */
Vertex moved;
for(size_t moving = 0; moving <= vertexSize; ++moving) {
/* Under each index is pointer to face which contains given vertex
and index of vertex in the face. */
std::unordered_map<Math::Vector<size_t, vertexSize>, HashedVertex, IndexHash> table;
/* Reserve space for all vertices */
table.reserve(this->vertices.size());
/* Go through all faces' vertices */
for(auto it = this->indices.begin(); it != this->indices.end(); ++it) {
/* Index of a vertex in vertexSize-dimensional table */
size_t index[vertexSize];
for(size_t ii = 0; ii != vertexSize; ++ii)
index[ii] = (this->vertices[*it][ii]+moved[ii]-min[ii])/epsilon;
/* Try inserting the vertex into table, if it already
exists, change vertex pointer of the face to already
existing vertex */
HashedVertex v(*it, table.size());
auto result = table.insert(std::pair<Math::Vector<size_t, vertexSize>, HashedVertex>(index, v));
*it = result.first->second.newIndex;
}
/* Shrink vertices array */
std::vector<Vertex> newVertices(table.size());
for(auto it = table.cbegin(); it != table.cend(); ++it)
newVertices[it->second.newIndex] = this->vertices[it->second.oldIndex];
std::swap(newVertices, this->vertices);
/* Move vertex coordinates by epsilon/2 in next direction */
if(moving != Vertex::Size) {
moved = Vertex();
moved[moving] = epsilon/2;
}
}
}
private:
class IndexHash {
public:
inline size_t operator()(const Math::Vector<size_t, vertexSize>& data) const {
size_t a = 0;
for(size_t i = 0; i != vertexSize; ++i)
a ^= data[i];
return a;
}
};
struct HashedVertex {
unsigned int oldIndex, newIndex;
HashedVertex(unsigned int oldIndex, unsigned int newIndex): oldIndex(oldIndex), newIndex(newIndex) {}
};
};
/**
@brief %Clean the mesh
@tparam Vertex Vertex data type (the same as in MeshBuilder)
@tparam vertexSize How many initial vertex fields are important (for example,
when dealing with perspective in 3D space, only first three fields of
otherwise 4D vertex are important)
@param builder %Mesh builder to operate on
@param epsilon Epsilon value, vertices nearer than this
distance will be melt together.
Removes duplicate vertices from the mesh.
This is convenience function supplementing direct usage of Clean class,
instead of
@code
MeshBuilder<T> builder;
MeshTools::Clean<T>(builder).run(epsilon);
@endcode
you can just write
@code
MeshTools::clean(builder, epsilon);
@endcode
However, when you want to specify @c vertexSize template parameter, you have
to explicitly specify both of them:
@code
MeshTools::clean<T, 3>(builder, epsilon);
@endcode
*/
template<class Vertex, size_t vertexSize = Vertex::Size> inline void clean(MeshBuilder<Vertex>& builder, typename Vertex::Type epsilon = EPSILON) {
Clean<Vertex, vertexSize>(builder).run(epsilon);
}
}}
#endif

102
src/MeshTools/Subdivide.h

@ -0,0 +1,102 @@
#ifndef Magnum_MeshTools_Subdivide_h
#define Magnum_MeshTools_Subdivide_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::Subdivide
*/
#include "AbstractTool.h"
namespace Magnum { namespace MeshTools {
/**
@brief %Mesh subdivisor implementation
See subdivide() for full documentation.
*/
template<class Vertex, class Interpolator> class Subdivide: public AbstractTool<Vertex> {
public:
/** @copydoc AbstractTool::AbstractTool() */
inline Subdivide(MeshBuilder<Vertex>& builder): AbstractTool<Vertex>(builder) {}
/**
* @brief Functor
*
* See subdivide() for full documentation.
*/
void run(Interpolator interpolator) {
size_t indexCount = this->indices.size();
this->indices.reserve(this->indices.size()*4);
/* Subdivide each face to four new */
for(size_t i = 0; i != indexCount; i += 3) {
/* Interpolate each side */
unsigned int newVertices[3];
for(int j = 0; j != 3; ++j)
newVertices[j] = this->builder.addVertex(interpolator(this->vertices[this->indices[i+j]], this->vertices[this->indices[i+(j+1)%3]]));
/*
* Add three new faces (0, 1, 3) and update original (2)
*
* orig 0
* / \
* / 0 \
* / \
* new 0 ----- new 2
* / \ / \
* / 1 \ 2 / 3 \
* / \ / \
* orig 1 ----- new 1 ---- orig 2
*/
this->builder.addFace(this->indices[i], newVertices[0], newVertices[2]);
this->builder.addFace(newVertices[0], this->indices[i+1], newVertices[1]);
this->builder.addFace(newVertices[2], newVertices[1], this->indices[i+2]);
for(size_t j = 0; j != 3; ++j)
this->indices[i+j] = newVertices[j];
}
}
};
/**
@brief %Subdivide the mesh
@tparam Vertex Vertex data type (the same as in MeshBuilder)
@tparam Interpolator See @c interpolator function parameter
@param builder %Mesh builder to operate on
@param interpolator Functor or function pointer which interpolates
two adjacent vertices: <tt>Vertex interpolator(Vertex a, Vertex b)</tt>
Goes through all triangle faces and subdivides them into four new. Cleaning
duplicate vertices in the mesh is up to user.
This is convenience function supplementing direct usage of Subdivide class,
instead of
@code
MeshBuilder<T> builder;
MeshTools::Subdivide<T, Interpolator>(builder).run(interpolator);
@endcode
you can just write
@code
MeshTools::subdivide(builder, interpolator);
@endcode
*/
template<class Vertex, class Interpolator> inline void subdivide(MeshBuilder<Vertex>& builder, Interpolator interpolator) {
Subdivide<Vertex, Interpolator>(builder).run(interpolator);
}
}}
#endif

4
src/MeshTools/Test/CMakeLists.txt

@ -0,0 +1,4 @@
corrade_add_test(CleanTest CleanTest.h CleanTest.cpp)
corrade_add_test(SubdivideTest SubdivideTest.h SubdivideTest.cpp)
corrade_add_test(SubdivideCleanBenchmark SubdivideCleanBenchmark.h SubdivideCleanBenchmark.cpp)
target_link_libraries(SubdivideCleanBenchmark ${MAGNUM_PRIMITIVES_LIBRARY})

44
src/MeshTools/Test/CleanTest.cpp

@ -0,0 +1,44 @@
/*
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 "CleanTest.h"
#include <QtTest/QTest>
#include "MeshTools/Clean.h"
QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::CleanTest)
using namespace std;
namespace Magnum { namespace MeshTools { namespace Test {
void CleanTest::cleanMesh() {
MeshBuilder<Vector1> builder;
builder.addVertex(1);
builder.addVertex(2);
builder.addVertex(1);
builder.addVertex(4);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
MeshTools::clean<Vector1, 1>(builder, 1);
/* Verify cleanup */
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 0, 1, 0, 2}));
}
}}}

48
src/MeshTools/Test/CleanTest.h

@ -0,0 +1,48 @@
#ifndef Magnum_MeshTools_Test_CleanTest_h
#define Magnum_MeshTools_Test_CleanTest_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 CleanTest: public QObject {
Q_OBJECT
private slots:
void cleanMesh();
private:
class Vector1 {
public:
static const size_t Size = 1;
typedef int Type;
Vector1(): data(0) {}
Vector1(int i): data(i) {}
int operator[](size_t i) const { return data; }
int& operator[](size_t i) { return data; }
bool operator==(Vector1 i) const { return i.data == data; }
Vector1 operator-(Vector1 i) const { return data-i.data; }
private:
int data;
};
};
}}}
#endif

78
src/MeshTools/Test/SubdivideCleanBenchmark.cpp

@ -0,0 +1,78 @@
/*
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 "SubdivideCleanBenchmark.h"
#include <QtTest/QTest>
#include "MeshBuilder.h"
#include "Primitives/Icosphere.h"
#include "MeshTools/Clean.h"
#include "MeshTools/Subdivide.h"
QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::SubdivideCleanBenchmark)
namespace Magnum { namespace MeshTools { namespace Test {
void SubdivideCleanBenchmark::subdivide() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
}
}
void SubdivideCleanBenchmark::subdivideAndCleanMeshAfter() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
}
}
void SubdivideCleanBenchmark::subdivideAndCleanMeshBetween() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
MeshTools::subdivide(builder, interpolator);
MeshTools::clean(builder);
}
}
}}}

11
src/Test/MeshBuilderBenchmark.h → src/MeshTools/Test/SubdivideCleanBenchmark.h

@ -1,5 +1,5 @@
#ifndef Magnum_Test_MeshBuilderBenchmark_h
#define Magnum_Test_MeshBuilderBenchmark_h
#ifndef Magnum_MeshTools_Test_SubdivideCleanBenchmark_h
#define Magnum_MeshTools_Test_SubdivideCleanBenchmark_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
@ -19,9 +19,9 @@
#include "Magnum.h"
namespace Magnum { namespace Test {
namespace Magnum { namespace MeshTools { namespace Test {
class MeshBuilderBenchmark: public QObject {
class SubdivideCleanBenchmark: public QObject {
Q_OBJECT
private slots:
@ -35,5 +35,6 @@ class MeshBuilderBenchmark: public QObject {
}
};
}}
}}}
#endif

51
src/MeshTools/Test/SubdivideTest.cpp

@ -0,0 +1,51 @@
/*
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 "SubdivideTest.h"
#include <QtTest/QTest>
#include "MeshBuilder.h"
#include "MeshTools/Clean.h"
#include "MeshTools/Subdivide.h"
QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::SubdivideTest)
using namespace std;
namespace Magnum { namespace MeshTools { namespace Test {
void SubdivideTest::subdivide() {
MeshBuilder<Vector1> builder;
builder.addVertex(0);
builder.addVertex(2);
builder.addVertex(6);
builder.addVertex(8);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
MeshTools::subdivide(builder, interpolator);
QVERIFY(builder.indices().size() == 24);
QVERIFY((builder.vertices() == vector<Vector1>{0, 2, 6, 8, 1, 4, 3, 4, 7, 5}));
QVERIFY((builder.indices() == vector<unsigned int>{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3}));
MeshTools::clean(builder, 1);
/* Vertices 0, 1, 2, 3, 4, 5, 6, 7, 8 */
QVERIFY(builder.vertices().size() == 9);
}
}}}

50
src/MeshTools/Test/SubdivideTest.h

@ -0,0 +1,50 @@
#ifndef Magnum_MeshTools_Test_SubdivideTest_h
#define Magnum_MeshTools_Test_SubdivideTest_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 SubdivideTest: public QObject {
Q_OBJECT
private slots:
void subdivide();
private:
class Vector1 {
public:
static const size_t Size = 1;
typedef int Type;
Vector1(): data(0) {}
Vector1(int i): data(i) {}
int operator[](size_t i) const { return data; }
int& operator[](size_t i) { return data; }
bool operator==(Vector1 i) const { return i.data == data; }
Vector1 operator-(Vector1 i) const { return data-i.data; }
private:
int data;
};
inline static Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; }
};
}}}
#endif

2
src/Test/CMakeLists.txt

@ -2,5 +2,3 @@ corrade_add_test(ObjectTest ObjectTest.h ObjectTest.cpp Magnum)
corrade_add_test(CameraTest CameraTest.h CameraTest.cpp Magnum)
corrade_add_test(SceneTest SceneTest.h SceneTest.cpp Magnum)
corrade_add_test(MeshBuilderTest MeshBuilderTest.h MeshBuilderTest.cpp Magnum)
corrade_add_test(MeshBuilderBenchmark MeshBuilderBenchmark.h MeshBuilderBenchmark.cpp Magnum)
target_link_libraries(MeshBuilderBenchmark ${MAGNUM_PRIMITIVES_LIBRARY})

77
src/Test/MeshBuilderBenchmark.cpp

@ -1,77 +0,0 @@
/*
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 "MeshBuilderBenchmark.h"
#include <QtTest/QTest>
#include "MeshBuilder.h"
#include "Magnum.h"
#include "Primitives/Icosphere.h"
QTEST_APPLESS_MAIN(Magnum::Test::MeshBuilderBenchmark)
namespace Magnum { namespace Test {
void MeshBuilderBenchmark::subdivide() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
}
}
void MeshBuilderBenchmark::subdivideAndCleanMeshAfter() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.subdivide(interpolator);
builder.cleanMesh();
}
}
void MeshBuilderBenchmark::subdivideAndCleanMeshBetween() {
QBENCHMARK {
MeshBuilder<Vector4> builder;
builder.setData(Primitives::Icosahedron::vertices, Primitives::Icosahedron::indices, 12, 60);
/* Subdivide 5 times */
builder.subdivide(interpolator);
builder.cleanMesh();
builder.subdivide(interpolator);
builder.cleanMesh();
builder.subdivide(interpolator);
builder.cleanMesh();
builder.subdivide(interpolator);
builder.cleanMesh();
builder.subdivide(interpolator);
builder.cleanMesh();
}
}
}}

47
src/Test/MeshBuilderTest.cpp

@ -26,18 +26,18 @@ using namespace std;
namespace Magnum { namespace Test {
void MeshBuilderTest::setData() {
MeshBuilder<Vector1> builder;
MeshBuilder<unsigned int> builder;
Vector1 vertexData[] = { 1, 2, 3, 4 };
unsigned int vertexData[] = { 1, 2, 3, 4 };
GLubyte indexData[] = { 0, 1, 2, 1, 2, 3 };
builder.setData(vertexData, indexData, 4, 6);
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 3, 4}));
QVERIFY((builder.vertices() == vector<unsigned int>{1, 2, 3, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 2, 1, 2, 3}));
}
void MeshBuilderTest::addFace() {
MeshBuilder<Vector1> builder;
MeshBuilder<unsigned int> builder;
builder.addVertex(1);
builder.addVertex(2);
builder.addVertex(3);
@ -45,45 +45,8 @@ void MeshBuilderTest::addFace() {
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 3, 4}));
QVERIFY((builder.vertices() == vector<unsigned int>{1, 2, 3, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 2, 1, 2, 3}));
}
void MeshBuilderTest::cleanMesh() {
MeshBuilder<Vector1> builder;
builder.addVertex(1);
builder.addVertex(2);
builder.addVertex(1);
builder.addVertex(4);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
builder.cleanMesh(1);
/* Verify cleanup */
QVERIFY((builder.vertices() == vector<Vector1>{1, 2, 4}));
QVERIFY((builder.indices() == vector<unsigned int>{0, 1, 0, 1, 0, 2}));
}
void MeshBuilderTest::subdivide() {
MeshBuilder<Vector1> builder;
builder.addVertex(0);
builder.addVertex(2);
builder.addVertex(6);
builder.addVertex(8);
builder.addFace(0, 1, 2);
builder.addFace(1, 2, 3);
builder.subdivide(interpolator);
QVERIFY(builder.indices().size() == 24);
QVERIFY((builder.vertices() == vector<Vector1>{0, 2, 6, 8, 1, 4, 3, 4, 7, 5}));
QVERIFY((builder.indices() == vector<unsigned int>{4, 5, 6, 7, 8, 9, 0, 4, 6, 4, 1, 5, 6, 5, 2, 1, 7, 9, 7, 2, 8, 9, 8, 3}));
builder.cleanMesh(1);
/* Vertices 0, 1, 2, 3, 4, 5, 6, 7, 8 */
QVERIFY(builder.vertices().size() == 9);
}
}}

22
src/Test/MeshBuilderTest.h

@ -25,28 +25,6 @@ class MeshBuilderTest: public QObject {
private slots:
void setData();
void addFace();
void cleanMesh();
void subdivide();
private:
class Vector1 {
public:
static const size_t Size = 1;
typedef int Type;
Vector1(): data(0) {}
Vector1(int i): data(i) {}
int operator[](size_t i) const { return data; }
int& operator[](size_t i) { return data; }
bool operator==(int i) const { return i == data; }
bool operator==(Vector1 i) const { return i.data == data; }
Vector1 operator-(Vector1 i) const { return data-i.data; }
private:
int data;
};
inline static Vector1 interpolator(Vector1 a, Vector1 b) { return (a[0]+b[0])/2; }
};
}}

Loading…
Cancel
Save