in UVAtlas/isochart/UVAtlas.cpp [244:453]
HRESULT UVAtlasPartitionInt(
_In_reads_(nVerts) const XMFLOAT3* positions,
_In_ size_t nVerts,
_When_(indexFormat == DXGI_FORMAT_R16_UINT, _In_reads_bytes_(nFaces * 3 * sizeof(uint16_t)))
_When_(indexFormat != DXGI_FORMAT_R16_UINT, _In_reads_bytes_(nFaces * 3 * sizeof(uint32_t))) const void* indices,
_In_ DXGI_FORMAT indexFormat,
_In_ size_t nFaces,
_In_ size_t maxChartNumber,
_In_ float maxStretch,
_In_reads_(nFaces * 3) const uint32_t* adjacency,
_In_reads_opt_(nFaces * 3) const uint32_t* falseEdgeAdjacency,
_In_reads_opt_(nFaces * 3) const float* pIMTArray,
_In_opt_ LPISOCHARTCALLBACK statusCallBack,
_In_ float callbackFrequency,
_In_ unsigned int options,
_Inout_ std::vector<UVAtlasVertex>& vMeshOutVertexBuffer,
_Inout_ std::vector<uint8_t>& vMeshOutIndexBuffer,
_Inout_opt_ std::vector<uint32_t>* pvFacePartitioning,
_Inout_opt_ std::vector<uint32_t>* pvVertexRemapArray,
_Inout_ std::vector<uint32_t>& vPartitionResultAdjacency,
_Out_opt_ float* maxStretchOut,
_Out_opt_ size_t* numChartsOut,
_In_ unsigned int uStageInfo)
{
if (!positions || !nVerts || !indices || !nFaces)
return E_INVALIDARG;
if (!adjacency)
{
DPF(0, "Input adjacency pointer cannot be nullptr. Use DirectXMesh to compute it");
return E_INVALIDARG;
}
switch (indexFormat)
{
case DXGI_FORMAT_R16_UINT:
if (nVerts >= UINT16_MAX)
return E_INVALIDARG;
break;
case DXGI_FORMAT_R32_UINT:
if (nVerts >= UINT32_MAX)
return E_INVALIDARG;
break;
default:
return E_INVALIDARG;
}
if ((uint64_t(nFaces) * 3) >= UINT32_MAX)
return HRESULT_E_ARITHMETIC_OVERFLOW;
if (maxChartNumber > nFaces)
maxChartNumber = nFaces;
HRESULT hr;
if (falseEdgeAdjacency)
{
for (size_t i = 0; i < 3 * nFaces; i++)
{
if ((adjacency[i] == uint32_t(-1)) &&
(falseEdgeAdjacency[i] != uint32_t(-1)))
{
DPF(0, "False edge found on triangle with no adjacent triangle.");
return HRESULT_E_INVALID_DATA;
}
}
// verify that for every false edge, the two vertices are connected by a path through
// non false-edges.
if (DXGI_FORMAT_R16_UINT == indexFormat)
{
hr = FalseEdgesConnected<uint16_t>(reinterpret_cast<const uint16_t*>(indices), adjacency, falseEdgeAdjacency, nFaces);
}
else
{
hr = FalseEdgesConnected<uint32_t>(reinterpret_cast<const uint32_t*>(indices), adjacency, falseEdgeAdjacency, nFaces);
}
if (FAILED(hr))
return hr;
}
std::vector<UVAtlasVertex> vOutVertexBuffer;
std::vector<uint8_t> vOutIndexBuffer;
std::vector<uint32_t> vOutVertexRemapArray;
std::vector<uint32_t> vOutFacePartitioning;
std::vector<uint32_t> vOutAdjacency;
size_t numCharts = 0;
float maxChartingStretch = 0.f;
hr = isochartpartition(positions,
nVerts,
sizeof(XMFLOAT3),
indexFormat,
indices,
nFaces,
reinterpret_cast<const FLOAT3*>(pIMTArray),
maxChartNumber,
maxStretch,
adjacency,
&vOutVertexBuffer,
&vOutIndexBuffer,
&vOutVertexRemapArray,
&vOutFacePartitioning,
&vOutAdjacency,
&numCharts,
&maxChartingStretch,
uStageInfo,
statusCallBack,
callbackFrequency,
falseEdgeAdjacency,
options);
if (FAILED(hr))
return hr;
if (DXGI_FORMAT_R16_UINT == indexFormat)
assert(nFaces * 3 * sizeof(uint16_t) == vOutIndexBuffer.size());
else
assert(nFaces * 3 * sizeof(uint32_t) == vOutIndexBuffer.size());
// the output remap array gives a remap that merges vertices that have the same
// position. So this really only gives data on where to get the output texture
// coordinates from for each vertex. The important thing is we need to detect
// if a vertex has been split, when this happens the output index buffer will
// have two triangles that have what was originally the same vertex, but now
// have different vertices
vOutVertexRemapArray.clear();
std::unique_ptr<uint32_t[]> forwardRemapArray;
size_t outMeshNumVertices = 0;
if (DXGI_FORMAT_R16_UINT == indexFormat)
{
hr = UVAtlasGetRealVertexRemap<uint16_t>(nFaces, nVerts, reinterpret_cast<const uint16_t*>(indices), reinterpret_cast<uint16_t*>(vOutIndexBuffer.data()),
&outMeshNumVertices, vOutVertexRemapArray, forwardRemapArray);
}
else
{
hr = UVAtlasGetRealVertexRemap<uint32_t>(nFaces, nVerts, reinterpret_cast<const uint32_t*>(indices), reinterpret_cast<uint32_t*>(vOutIndexBuffer.data()),
&outMeshNumVertices, vOutVertexRemapArray, forwardRemapArray);
}
if (FAILED(hr))
return hr;
// make sure we didn't lose vertices, or change the number of faces or switch the format
assert(outMeshNumVertices >= nVerts);
// clone old mesh, copy in new vertex buffer and index buffer
try
{
vMeshOutVertexBuffer.resize(outMeshNumVertices);
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
// copy old vertex data using remap array
{
auto bBaseIn = reinterpret_cast<const uint8_t*>(positions);
auto bBaseOut = vMeshOutVertexBuffer.data();
uint32_t* pdwRemap = vOutVertexRemapArray.data();
auto pOutVerts = vOutVertexBuffer.data();
uint32_t* pForwardRemapArray = forwardRemapArray.get();
for (size_t i = 0; i < outMeshNumVertices; i++)
{
memcpy(&bBaseOut[i].pos.x, bBaseIn + pdwRemap[i] * sizeof(XMFLOAT3), sizeof(XMFLOAT3));
if (pForwardRemapArray[i] == uint32_t(-1))
{
bBaseOut[i].uv.x = bBaseOut[i].uv.y = 0.f;
}
else
{
bBaseOut[i].uv.x = pOutVerts[pForwardRemapArray[i]].uv.x;
bBaseOut[i].uv.y = pOutVerts[pForwardRemapArray[i]].uv.y;
}
}
}
// copy index data from OutIndexBuffer to the index buffer
std::swap(vMeshOutIndexBuffer, vOutIndexBuffer);
if (maxStretchOut)
{
*maxStretchOut = maxChartingStretch;
}
if (numChartsOut)
{
*numChartsOut = numCharts;
}
if (pvFacePartitioning)
{
std::swap(*pvFacePartitioning, vOutFacePartitioning);
}
if (pvVertexRemapArray)
{
std::swap(*pvVertexRemapArray, vOutVertexRemapArray);
}
std::swap(vPartitionResultAdjacency, vOutAdjacency);
return S_OK;
}