HRESULT DirectX::FinalizeVBAndPointReps()

in DirectXMesh/DirectXMeshRemap.cpp [707:835]


HRESULT DirectX::FinalizeVBAndPointReps(
    const void* vbin,
    size_t stride,
    size_t nVerts,
    const uint32_t* prin,
    const uint32_t* dupVerts,
    size_t nDupVerts,
    const uint32_t* vertexRemap,
    void* vbout,
    uint32_t* prout) noexcept
{
    if (!vbin || !stride || !nVerts || !prin || !vbout || !prout)
        return E_INVALIDARG;

    if (!dupVerts && !vertexRemap)
        return E_INVALIDARG;

    if (dupVerts && !nDupVerts)
        return E_INVALIDARG;

    if (!dupVerts && nDupVerts > 0)
        return E_INVALIDARG;

    if (nVerts >= UINT32_MAX)
        return E_INVALIDARG;

    if (stride > c_MaxStride)
        return E_INVALIDARG;

    if ((uint64_t(nVerts) + uint64_t(nDupVerts)) >= UINT32_MAX)
        return HRESULT_E_ARITHMETIC_OVERFLOW;

    if (vbin == vbout)
        return HRESULT_E_NOT_SUPPORTED;

    size_t newVerts = nVerts + nDupVerts;

    std::unique_ptr<uint32_t[]> vertexRemapInverse;
    if (vertexRemap)
    {
        vertexRemapInverse.reset(new (std::nothrow) uint32_t[newVerts]);
        if (!vertexRemapInverse)
            return E_OUTOFMEMORY;

        memset(vertexRemapInverse.get(), 0xff, sizeof(uint32_t) * newVerts);

        for (uint32_t j = 0; j < newVerts; ++j)
        {
            if (vertexRemap[j] != UNUSED32)
            {
                if (vertexRemap[j] >= newVerts)
                    return E_INVALIDARG;

                vertexRemapInverse[vertexRemap[j]] = j;
            }
        }
    }

    auto sptr = static_cast<const uint8_t*>(vbin);
    auto dptr = static_cast<uint8_t*>(vbout);

#ifdef _DEBUG
    memset(vbout, 0, newVerts * stride);
#endif

    std::unique_ptr<uint32_t[]> pointRep(new (std::nothrow) uint32_t[nVerts + nDupVerts]);
    if (!pointRep)
        return E_OUTOFMEMORY;

    memcpy(pointRep.get(), prin, sizeof(uint32_t) * nVerts);

    for (size_t i = 0; i < nDupVerts; ++i)
    {
        pointRep[i + nVerts] = prin[dupVerts[i]];
    }

    for (size_t j = 0; j < newVerts; ++j)
    {
        uint32_t src = (vertexRemap) ? vertexRemap[j] : uint32_t(j);

        if (src == UNUSED32)
        {
            // remap entry is unused
        }
        else if (src >= newVerts)
        {
            return E_FAIL;
        }
        else if (src < nVerts)
        {
            memcpy(dptr, sptr + src * stride, stride);

            uint32_t pr = pointRep[src];
            if (pr < newVerts)
            {
                prout[j] = (vertexRemapInverse) ? vertexRemapInverse[pr] : pr;
            }
        }
        else if (dupVerts)
        {
            uint32_t dup = dupVerts[src - nVerts];
            memcpy(dptr, sptr + dup * stride, stride);

            uint32_t pr = pointRep[src];
            if (pr < newVerts)
            {
                prout[j] = (vertexRemapInverse) ? vertexRemapInverse[pr] : pr;
            }
        }
        else
            return E_FAIL;

        dptr += stride;
    }

    if (vertexRemap)
    {
        // clean up point reps for any removed vertices
        for (uint32_t i = 0; i < newVerts; ++i)
        {
            if (vertexRemap[i] == UNUSED32)
            {
                pointRep[i] = UNUSED32;
            }
        }
    }

    return S_OK;
}