|
@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#include <unordered_set>
|
|
#include <unordered_set>
|
|
#include <unordered_map>
|
|
#include <unordered_map>
|
|
#include <memory>
|
|
#include <memory>
|
|
|
|
+#include <map>
|
|
|
|
|
|
using namespace Assimp;
|
|
using namespace Assimp;
|
|
|
|
|
|
@@ -99,52 +100,6 @@ void JoinVerticesProcess::Execute( aiScene* pScene) {
|
|
|
|
|
|
namespace {
|
|
namespace {
|
|
|
|
|
|
-bool areVerticesEqual(
|
|
|
|
- const Vertex &lhs,
|
|
|
|
- const Vertex &rhs,
|
|
|
|
- unsigned numUVChannels,
|
|
|
|
- unsigned numColorChannels) {
|
|
|
|
- // A little helper to find locally close vertices faster.
|
|
|
|
- // Try to reuse the lookup table from the last step.
|
|
|
|
- const static float epsilon = 1e-5f;
|
|
|
|
- // Squared because we check against squared length of the vector difference
|
|
|
|
- static const float squareEpsilon = epsilon * epsilon;
|
|
|
|
-
|
|
|
|
- // Square compare is useful for animeshes vertices compare
|
|
|
|
- if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // We just test the other attributes even if they're not present in the mesh.
|
|
|
|
- // In this case they're initialized to 0 so the comparison succeeds.
|
|
|
|
- // By this method the non-present attributes are effectively ignored in the comparison.
|
|
|
|
- if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (unsigned i = 0; i < numUVChannels; i++) {
|
|
|
|
- if ((lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (unsigned i = 0; i < numColorChannels; i++) {
|
|
|
|
- if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
template<class XMesh>
|
|
template<class XMesh>
|
|
void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
|
|
void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
|
|
// replace vertex data with the unique data sets
|
|
// replace vertex data with the unique data sets
|
|
@@ -157,7 +112,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
|
|
// ----------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
// Position, if present (check made for aiAnimMesh)
|
|
// Position, if present (check made for aiAnimMesh)
|
|
- if (pMesh->mVertices) {
|
|
|
|
|
|
+ if (pMesh->mVertices) {
|
|
std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
|
|
std::unique_ptr<aiVector3D[]> oldVertices(pMesh->mVertices);
|
|
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
|
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
|
|
for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
|
for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
|
@@ -204,41 +159,6 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<int> &uniqueVertices) {
|
|
} // namespace
|
|
} // namespace
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------
|
|
-// Unites identical vertices in the given mesh
|
|
|
|
-// combine hashes
|
|
|
|
-inline void hash_combine(std::size_t &) {
|
|
|
|
- // empty
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-template <typename T, typename... Rest>
|
|
|
|
-inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
|
|
|
- std::hash<T> hasher;
|
|
|
|
- seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
|
|
|
- hash_combine(seed, rest...);
|
|
|
|
-}
|
|
|
|
-//template specialization for std::hash for Vertex
|
|
|
|
-template<>
|
|
|
|
-struct std::hash<Vertex> {
|
|
|
|
- std::size_t operator()(Vertex const& v) const noexcept {
|
|
|
|
- size_t seed = 0;
|
|
|
|
- hash_combine(seed, v.position.x ,v.position.y,v.position.z);
|
|
|
|
- return seed;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-//template specialization for std::equal_to for Vertex
|
|
|
|
-template<>
|
|
|
|
-struct std::equal_to<Vertex> {
|
|
|
|
- equal_to(unsigned numUVChannels, unsigned numColorChannels) :
|
|
|
|
- mNumUVChannels(numUVChannels),
|
|
|
|
- mNumColorChannels(numColorChannels) {}
|
|
|
|
- bool operator()(const Vertex &lhs, const Vertex &rhs) const {
|
|
|
|
- return areVerticesEqual(lhs, rhs, mNumUVChannels, mNumColorChannels);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-private:
|
|
|
|
- unsigned mNumUVChannels;
|
|
|
|
- unsigned mNumColorChannels;
|
|
|
|
-};
|
|
|
|
|
|
|
|
static constexpr size_t JOINED_VERTICES_MARK = 0x80000000u;
|
|
static constexpr size_t JOINED_VERTICES_MARK = 0x80000000u;
|
|
|
|
|
|
@@ -266,7 +186,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
|
|
|
|
|
|
// We'll never have more vertices afterwards.
|
|
// We'll never have more vertices afterwards.
|
|
std::vector<int> uniqueVertices;
|
|
std::vector<int> uniqueVertices;
|
|
- uniqueVertices.reserve( pMesh->mNumVertices);
|
|
|
|
|
|
|
|
// For each vertex the index of the vertex it was replaced by.
|
|
// For each vertex the index of the vertex it was replaced by.
|
|
// Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
|
|
// Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark
|
|
@@ -276,31 +195,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
|
|
static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
|
|
static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff");
|
|
std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
|
|
std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
|
|
|
|
|
|
- // float posEpsilonSqr;
|
|
|
|
- SpatialSort *vertexFinder = nullptr;
|
|
|
|
- SpatialSort _vertexFinder;
|
|
|
|
-
|
|
|
|
- typedef std::pair<SpatialSort,float> SpatPair;
|
|
|
|
- if (shared) {
|
|
|
|
- std::vector<SpatPair >* avf;
|
|
|
|
- shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
|
|
|
- if (avf) {
|
|
|
|
- SpatPair& blubb = (*avf)[meshIndex];
|
|
|
|
- vertexFinder = &blubb.first;
|
|
|
|
- // posEpsilonSqr = blubb.second;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (!vertexFinder) {
|
|
|
|
- // bad, need to compute it.
|
|
|
|
- _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
|
|
|
- vertexFinder = &_vertexFinder;
|
|
|
|
- // posEpsilonSqr = ComputePositionEpsilon(pMesh);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Again, better waste some bytes than a realloc ...
|
|
|
|
- std::vector<unsigned int> verticesFound;
|
|
|
|
- verticesFound.reserve(10);
|
|
|
|
-
|
|
|
|
// Run an optimized code path if we don't have multiple UVs or vertex colors.
|
|
// Run an optimized code path if we don't have multiple UVs or vertex colors.
|
|
// This should yield false in more than 99% of all imports ...
|
|
// This should yield false in more than 99% of all imports ...
|
|
const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
|
|
const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
|
|
@@ -314,14 +208,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// a map that maps a vertex to its new index
|
|
// a map that maps a vertex to its new index
|
|
- const auto numBuckets = pMesh->mNumVertices;
|
|
|
|
- const auto hasher = std::hash<Vertex>();
|
|
|
|
- const auto comparator = std::equal_to<Vertex>(
|
|
|
|
- pMesh->GetNumUVChannels(),
|
|
|
|
- pMesh->GetNumColorChannels());
|
|
|
|
- std::unordered_map<Vertex, int> vertex2Index(numBuckets, hasher, comparator);
|
|
|
|
|
|
+ std::map<Vertex, int> vertex2Index = {};
|
|
// we can not end up with more vertices than we started with
|
|
// we can not end up with more vertices than we started with
|
|
- vertex2Index.reserve(pMesh->mNumVertices);
|
|
|
|
// Now check each vertex if it brings something new to the table
|
|
// Now check each vertex if it brings something new to the table
|
|
int newIndex = 0;
|
|
int newIndex = 0;
|
|
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
|
for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
|
@@ -336,8 +224,8 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
|
|
// if the vertex is not in the map then it is a new vertex add it.
|
|
// if the vertex is not in the map then it is a new vertex add it.
|
|
if (it == vertex2Index.end()) {
|
|
if (it == vertex2Index.end()) {
|
|
// this is a new vertex give it a new index
|
|
// this is a new vertex give it a new index
|
|
- vertex2Index[v] = newIndex;
|
|
|
|
- //keep track of its index and increment 1
|
|
|
|
|
|
+ vertex2Index.emplace(v, newIndex);
|
|
|
|
+ // keep track of its index and increment 1
|
|
replaceIndex[a] = newIndex++;
|
|
replaceIndex[a] = newIndex++;
|
|
// add the vertex to the unique vertices
|
|
// add the vertex to the unique vertices
|
|
uniqueVertices.push_back(a);
|
|
uniqueVertices.push_back(a);
|