HRESULT CUVAtlasRepacker::GenerateNewBuffers()

in UVAtlas/isochart/UVAtlasRepacker.cpp [825:997]


HRESULT CUVAtlasRepacker::GenerateNewBuffers()
{
    // create an attribute buffer
    m_vAttributeBuffer.resize(m_iNumFaces);

    auto pAB = m_vAttributeBuffer.data();
    for (size_t i = 0; i < m_iNumFaces; i++)
        pAB[i] = uint32_t(-1);

    try
    {
        m_NewAdjacentInfo.resize(m_iNumFaces * 3);
        m_VertexBuffer.reserve(m_iNumVertices);
        m_IndexBuffer.reserve(m_iNumFaces * 3);
        m_IndexPartition.resize(m_iNumVertices);

        for (size_t i = 0; i < m_iNumVertices; i++)
            m_IndexPartition[i] = uint32_t(-1);

        auto pVB = reinterpret_cast<const uint8_t*>(m_pvVertexBuffer->data());
        auto pIB = reinterpret_cast<const uint8_t*>(m_pvIndexBuffer->data());

        UVATLASATTRIBUTERANGE ar;

        std::unique_ptr<bool[]> bUsedFace(new (std::nothrow) bool[m_iNumFaces]);
        if (!bUsedFace)
            return E_OUTOFMEMORY;

        memset(bUsedFace.get(), 0, sizeof(bool) * m_iNumFaces);

        std::vector<uint32_t> ab;
        uint32_t num = 0;
        uint32_t indexnum = 0;
        uint32_t facestart = 0;
        for (uint32_t i = 0; i < m_iNumFaces; i++)
        {
            if (pAB[i] == uint32_t(-1))
            {
                ab.clear();
                if (!bUsedFace[i])
                {
                    ab.push_back(i);
                    bUsedFace[i] = true;
                }
                size_t t = 0;

                // use broad-first search algorithm to find chart
                // store the result into m_pAttributeBuffer 
                if (m_pPartitionAdj)
                {
                    while (t < ab.size())
                    {
                        pAB[ab[t]] = uint32_t(num);
                        for (uint32_t j = 0; j < 3; j++)
                        {
                            uint32_t index = 3 * ab[t] + j;
                            if (m_AdjacentInfo[index] != uint32_t(-1) && !bUsedFace[m_AdjacentInfo[index]])
                            {
                                ab.push_back(m_AdjacentInfo[index]);
                                bUsedFace[m_AdjacentInfo[index]] = true;
                            }
                        }
                        t++;
                    }
                }
                else
                {
                    while (t < ab.size())
                    {
                        pAB[ab[t]] = uint32_t(num);
                        for (size_t j = 0; j < 3; j++)
                        {
                            uint32_t index = *reinterpret_cast<const T*>(pIB + (3 * ab[t] + j) * sizeof(T));
                            for (size_t k = 0; k < m_VertexAdjInfo[index].size(); k++)
                                if (!bUsedFace[m_VertexAdjInfo[index][k]])
                                {
                                    ab.push_back(m_VertexAdjInfo[index][k]);
                                    bUsedFace[m_VertexAdjInfo[index][k]] = true;
                                }
                        }
                        t++;
                    }
                }

                // after found a set of vertices that belong to the same chart we store them 
                // continuously in new vertex buffers.
                ar.VertexStart = uint32_t(m_VertexBuffer.size());

                // iterate every triangle in the same chart
                for (size_t j = 0; j < ab.size(); j++)
                {

                    // find the original index of the triangle's vertex
                    uint32_t index1 = *reinterpret_cast<const T*>(pIB + 3 * ab[j] * sizeof(T));
                    uint32_t index2 = *reinterpret_cast<const T*>(pIB + (3 * ab[j] + 1) * sizeof(T));
                    uint32_t index3 = *reinterpret_cast<const T*>(pIB + (3 * ab[j] + 2) * sizeof(T));

                    // copy the original adjacent information continuously in new adjacent buffer
                    memcpy(&m_NewAdjacentInfo[j * 3 + facestart * 3],
                        &m_AdjacentInfo[3 * ab[j]], sizeof(uint32_t) * 3);

                    // copy the original index information continuously in new index buffer
                    m_IndexBuffer.push_back(index1);
                    m_IndexBuffer.push_back(index2);
                    m_IndexBuffer.push_back(index3);

                    // find the original UV coordinates of each vertex
                    auto p1 = reinterpret_cast<const XMFLOAT2*>(pVB + index1 * m_iNumBytesPerVertex + m_TexCoordOffset);
                    auto p2 = reinterpret_cast<const XMFLOAT2*>(pVB + index2 * m_iNumBytesPerVertex + m_TexCoordOffset);
                    auto p3 = reinterpret_cast<const XMFLOAT2*>(pVB + index3 * m_iNumBytesPerVertex + m_TexCoordOffset);

                    // find the original 3D coordinates of each vertex
                    auto pp1 = reinterpret_cast<const XMFLOAT3*>(pVB + index1 * m_iNumBytesPerVertex);
                    auto pp2 = reinterpret_cast<const XMFLOAT3*>(pVB + index2 * m_iNumBytesPerVertex);
                    auto pp3 = reinterpret_cast<const XMFLOAT3*>(pVB + index3 * m_iNumBytesPerVertex);

                    // create an index partition buffer which store each vertex's original position
                    // to recover the vertex buffer after repacking.
                    if (m_IndexPartition[index1] == uint32_t(-1))
                    {
                        m_IndexPartition[index1] = indexnum++;
                        UVAtlasVertex vert;
                        vert.pos.x = pp1->x;
                        vert.pos.y = pp1->y;
                        vert.pos.z = pp1->z;
                        vert.uv.x = p1->x;
                        vert.uv.y = p1->y;
                        m_VertexBuffer.push_back(vert);
                    }
                    if (m_IndexPartition[index2] == uint32_t(-1))
                    {
                        m_IndexPartition[index2] = indexnum++;
                        UVAtlasVertex vert;
                        vert.pos.x = pp2->x;
                        vert.pos.y = pp2->y;
                        vert.pos.z = pp2->z;
                        vert.uv.x = p2->x;
                        vert.uv.y = p2->y;
                        m_VertexBuffer.push_back(vert);
                    }
                    if (m_IndexPartition[index3] == uint32_t(-1))
                    {
                        m_IndexPartition[index3] = indexnum++;
                        UVAtlasVertex vert;
                        vert.pos.x = pp3->x;
                        vert.pos.y = pp3->y;
                        vert.pos.z = pp3->z;
                        vert.uv.x = p3->x;
                        vert.uv.y = p3->y;
                        m_VertexBuffer.push_back(vert);
                    }
                }

                // store the newly found chart's information into m_AttrTable which
                // represent the attribute table
                ar.VertexCount = static_cast<uint32_t>(m_VertexBuffer.size() - ar.VertexStart);
                ar.FaceCount = static_cast<uint32_t>(ab.size());
                ar.FaceStart = facestart;
                ar.AttribId = num;
                facestart += static_cast<uint32_t>(ab.size());
                m_AttrTable.push_back(ar);
                num++;
            }
        }
        m_iNumCharts = size_t(num);
    }
    catch (...)
    {
        return E_OUTOFMEMORY;
    }

    return S_OK;
}