void PTexMesh::CalculateAdjacency()

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