in DirectXMesh/DirectXMeshValidate.cpp [39:254]
HRESULT ValidateIndices(
_In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces,
_In_ size_t nVerts, _In_reads_opt_(nFaces * 3) const uint32_t* adjacency,
_In_ VALIDATE_FLAGS flags, _In_opt_ std::wstring* msgs)
{
bool result = true;
if (!adjacency)
{
if (flags & VALIDATE_BACKFACING)
{
if (msgs)
*msgs += L"Missing adjacency information required to check for BACKFACING\n";
result = false;
}
if (flags & VALIDATE_ASYMMETRIC_ADJ)
{
if (msgs)
*msgs += L"Missing adjacency information required to check for ASYMMETRIC_ADJ\n";
result = false;
}
if (!result)
return E_INVALIDARG;
}
for (size_t face = 0; face < nFaces; ++face)
{
// Check for values in-range
for (size_t point = 0; point < 3; ++point)
{
index_t i = indices[face * 3 + point];
if (i >= nVerts && i != index_t(-1))
{
if (!msgs)
return E_FAIL;
result = false;
wchar_t buff[128] = {};
swprintf_s(buff, L"An invalid index value (%u) was found on face %zu\n", i, face);
*msgs += buff;
}
if (adjacency)
{
uint32_t j = adjacency[face * 3 + point];
if (j >= nFaces && j != UNUSED32)
{
if (!msgs)
return E_FAIL;
result = false;
wchar_t buff[128] = {};
swprintf_s(buff, L"An invalid neighbor index value (%u) was found on face %zu\n", j, face);
*msgs += buff;
}
}
}
// Check for unused faces
index_t i0 = indices[face * 3];
index_t i1 = indices[face * 3 + 1];
index_t i2 = indices[face * 3 + 2];
if (i0 == index_t(-1)
|| i1 == index_t(-1)
|| i2 == index_t(-1))
{
if (flags & VALIDATE_UNUSED)
{
if (i0 != i1
|| i0 != i2
|| i1 != i2)
{
if (!msgs)
return E_FAIL;
result = false;
wchar_t buff[128] = {};
swprintf_s(buff, L"An unused face (%zu) contains 'valid' but ignored vertices (%u,%u,%u)\n", face, i0, i1, i2);
*msgs += buff;
}
if (adjacency)
{
for (size_t point = 0; point < 3; ++point)
{
uint32_t k = adjacency[face * 3 + point];
if (k != UNUSED32)
{
if (!msgs)
return E_FAIL;
result = false;
wchar_t buff[128] = {};
swprintf_s(buff, L"An unused face (%zu) has a neighbor %u\n", face, k);
*msgs += buff;
}
}
}
}
// ignore unused triangles for remaining tests
continue;
}
// Check for degenerate triangles
if (i0 == i1
|| i0 == i2
|| i1 == i2)
{
if (flags & VALIDATE_DEGENERATE)
{
if (!msgs)
return E_FAIL;
result = false;
index_t bad;
if (i0 == i1)
bad = i0;
else if (i1 == i2)
bad = i2;
else
bad = i0;
wchar_t buff[128] = {};
swprintf_s(buff, L"A point (%u) was found more than once in triangle %zu\n", bad, face);
*msgs += buff;
if (adjacency)
{
for (size_t point = 0; point < 3; ++point)
{
uint32_t k = adjacency[face * 3 + point];
if (k != UNUSED32)
{
result = false;
swprintf_s(buff, L"A degenerate face (%zu) has a neighbor %u\n", face, k);
*msgs += buff;
}
}
}
}
// ignore degenerate triangles for remaining tests
continue;
}
// Check for symmetric neighbors
if ((flags & VALIDATE_ASYMMETRIC_ADJ) && adjacency)
{
for (size_t point = 0; point < 3; ++point)
{
uint32_t k = adjacency[face * 3 + point];
if (k == UNUSED32)
continue;
assert(k < nFaces);
uint32_t edge = find_edge<uint32_t>(&adjacency[k * 3], uint32_t(face));
if (edge >= 3)
{
if (!msgs)
return E_FAIL;
result = false;
wchar_t buff[256] = {};
swprintf_s(buff, L"A neighbor triangle (%u) does not reference back to this face (%zu) as expected\n", k, face);
*msgs += buff;
}
}
}
// Check for duplicate neighbor
if ((flags & VALIDATE_BACKFACING) && adjacency)
{
uint32_t j0 = adjacency[face * 3];
uint32_t j1 = adjacency[face * 3 + 1];
uint32_t j2 = adjacency[face * 3 + 2];
if ((j0 == j1 && j0 != UNUSED32)
|| (j0 == j2 && j0 != UNUSED32)
|| (j1 == j2 && j1 != UNUSED32))
{
if (!msgs)
return E_FAIL;
result = false;
uint32_t bad;
if (j0 == j1 && j0 != UNUSED32)
bad = j0;
else if (j0 == j2 && j0 != UNUSED32)
bad = j0;
else
bad = j1;
wchar_t buff[256] = {};
swprintf_s(buff, L"A neighbor triangle (%u) was found more than once on triangle %zu\n"
L"\t(likley problem is that two triangles share same points with opposite direction)\n", bad, face);
*msgs += buff;
}
}
}
return result ? S_OK : E_FAIL;
}