in ReplicaSDK/ptex/PTexLib.cpp [358:433]
void PTexMesh::CalculateAdjacency(const MeshData& mesh, std::vector<uint32_t>& adjFaces) {
struct EdgeData {
EdgeData(int f, int e) : face(f), edge(e) {}
int face;
int edge;
};
std::unordered_map<uint64_t, std::vector<EdgeData>> edgeMap;
ASSERT(mesh.polygonStride == 4, "Only works on quad meshes");
size_t numFaces = mesh.ibo.size() / mesh.polygonStride;
pangolin::ManagedImage<std::unordered_map<uint64_t, std::vector<EdgeData>>::iterator>
edgeIterators(mesh.polygonStride, numFaces);
// for each face
for (size_t f = 0; f < numFaces; f++) {
// for each edge
for (int e = 0; e < (int)mesh.polygonStride; e++) {
// add to edge to face map
const uint32_t i0 = mesh.ibo[f * mesh.polygonStride + e];
const uint32_t i1 = mesh.ibo[f * mesh.polygonStride + ((e + 1) % mesh.polygonStride)];
const uint64_t key = (uint64_t)std::min(i0, i1) << 32 | (uint32_t)std::max(i0, i1);
const EdgeData edgeData(f, e);
auto it = edgeMap.find(key);
if (it == edgeMap.end()) {
it = edgeMap.emplace(key, std::vector<EdgeData>()).first;
it->second.reserve(4);
it->second.push_back(edgeData);
} else {
it->second.push_back(edgeData);
}
edgeIterators(e, f) = it;
}
}
adjFaces.resize(numFaces * mesh.polygonStride);
for (size_t f = 0; f < numFaces; f++) {
for (int e = 0; e < (int)mesh.polygonStride; e++) {
auto it = edgeIterators(e, f);
const std::vector<EdgeData>& adj = it->second;
// find adjacent face
int adjFace = -1;
for (size_t i = 0; i < adj.size(); i++) {
if (adj[i].face != (int)f)
adjFace = adj[i].face;
}
// find number of 90 degree rotation steps between faces
int rot = 0;
if (adj.size() == 2) {
int edge0 = 0, edge1 = 0;
if (adj[0].edge == e) {
edge0 = adj[0].edge;
edge1 = adj[1].edge;
} else if (adj[1].edge == e) {
edge0 = adj[1].edge;
edge1 = adj[0].edge;
}
rot = (edge0 - edge1 + 2) & 3;
}
// pack adjacent face and rotation into 32-bit int
adjFaces[f * mesh.polygonStride + e] = (rot << ROTATION_SHIFT) | (adjFace & FACE_MASK);
}
}
}