HRESULT UVAtlasPartitionInt()

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