in DirectXMesh/DirectXMeshOptimizeTVC.cpp [588:764]
HRESULT VertexCacheStripReorderImpl(
_In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces,
_In_reads_(nFaces * 3) const uint32_t* adjacency,
_In_reads_opt_(nFaces) const uint32_t* attributes,
_Out_writes_(nFaces) uint32_t* faceRemap,
uint32_t vertexCache, uint32_t restart)
{
auto subsets = ComputeSubsets(attributes, nFaces);
assert(!subsets.empty());
mesh_status<index_t> status;
HRESULT hr = status.initialize(indices, nFaces, adjacency, subsets);
if (FAILED(hr))
return hr;
sim_vcache vcache;
hr = vcache.initialize(vertexCache);
if (FAILED(hr))
return hr;
std::unique_ptr<uint32_t[]> faceRemapInverse(new (std::nothrow) uint32_t[nFaces]);
if (!faceRemapInverse)
return E_OUTOFMEMORY;
memset(faceRemapInverse.get(), 0xff, sizeof(uint32_t) * nFaces);
assert(vertexCache >= restart);
uint32_t desired = vertexCache - restart;
for (const auto& it : subsets)
{
hr = status.setSubset(indices, nFaces, it.first, it.second);
if (FAILED(hr))
return hr;
vcache.clear();
uint32_t locnext = 0;
facecorner_t nextCorner(UNUSED32, UNUSED32);
facecorner_t curCorner(UNUSED32, UNUSED32);
uint32_t curface = 0;
for (;;)
{
assert(nextCorner.first == UNUSED32);
curCorner.first = status.find_initial();
if (curCorner.first == UNUSED32)
break;
uint32_t n0 = status.get_neighbors(curCorner.first, 0);
if ((n0 != UNUSED32) && !status.isprocessed(n0))
{
curCorner.second = 1;
}
else
{
uint32_t n1 = status.get_neighbors(curCorner.first, 1);
if ((n1 != UNUSED32) && !status.isprocessed(n1))
{
curCorner.second = 2;
}
else
{
curCorner.second = 0;
}
}
bool striprestart = false;
for (;;)
{
assert(curCorner.first != UNUSED32);
assert(!status.isprocessed(curCorner.first));
// Decision: either add a ring of faces or restart strip
if (nextCorner.first != UNUSED32)
{
uint32_t nf = 0;
for (facecorner_t temp = curCorner; ; )
{
facecorner_t next = counterclockwise_corner<index_t>(temp, status);
if ((next.first == UNUSED32) || status.isprocessed(next.first))
break;
++nf;
temp = next;
}
if (locnext + nf > desired)
{
// restart
if (!status.isprocessed(nextCorner.first))
{
curCorner = nextCorner;
}
nextCorner.first = UNUSED32;
}
}
for (;;)
{
assert(curCorner.first != UNUSED32);
status.mark(curCorner.first);
faceRemapInverse[curCorner.first] = uint32_t(curface + it.first);
curface += 1;
assert(indices[curCorner.first * 3] != index_t(-1));
if (!vcache.access(indices[curCorner.first * 3]))
locnext += 1;
assert(indices[curCorner.first * 3 + 1] != index_t(-1));
if (!vcache.access(indices[curCorner.first * 3 + 1]))
locnext += 1;
assert(indices[curCorner.first * 3 + 2] != index_t(-1));
if (!vcache.access(indices[curCorner.first * 3 + 2]))
locnext += 1;
facecorner_t intCorner = counterclockwise_corner<index_t>(curCorner, status);
bool interiornei = (intCorner.first != UNUSED32) && !status.isprocessed(intCorner.first);
facecorner_t extCorner = counterclockwise_corner<index_t>(facecorner_t(curCorner.first, (curCorner.second + 2) % 3), status);
bool exteriornei = (extCorner.first != UNUSED32) && !status.isprocessed(extCorner.first);
if (interiornei)
{
if (exteriornei)
{
if (nextCorner.first == UNUSED32)
{
nextCorner = extCorner;
locnext = 0;
}
}
curCorner = intCorner;
}
else if (exteriornei)
{
curCorner = extCorner;
break;
}
else
{
curCorner = nextCorner;
nextCorner.first = UNUSED32;
if ((curCorner.first == UNUSED32) || status.isprocessed(curCorner.first))
{
striprestart = true;
break;
}
}
}
if (striprestart)
break;
}
}
}
// inverse remap
memset(faceRemap, 0xff, sizeof(uint32_t) * nFaces);
for (uint32_t j = 0; j < nFaces; ++j)
{
uint32_t f = faceRemapInverse[j];
if (f < nFaces)
{
faceRemap[f] = j;
}
}
return S_OK;
}