HRESULT VertexCacheStripReorderImpl()

in DirectXMesh/DirectXMeshOptimizeTVC.cpp [588:764]


    HRESULT VertexCacheStripReorderImpl(
        _In_reads_(nFaces * 3) const index_t* indices, _In_ size_t nFaces,
        _In_reads_(nFaces * 3) const uint32_t* adjacency,
        _In_reads_opt_(nFaces) const uint32_t* attributes,
        _Out_writes_(nFaces) uint32_t* faceRemap,
        uint32_t vertexCache, uint32_t restart)
    {
        auto subsets = ComputeSubsets(attributes, nFaces);

        assert(!subsets.empty());

        mesh_status<index_t> status;
        HRESULT hr = status.initialize(indices, nFaces, adjacency, subsets);
        if (FAILED(hr))
            return hr;

        sim_vcache vcache;
        hr = vcache.initialize(vertexCache);
        if (FAILED(hr))
            return hr;

        std::unique_ptr<uint32_t[]> faceRemapInverse(new (std::nothrow) uint32_t[nFaces]);
        if (!faceRemapInverse)
            return E_OUTOFMEMORY;

        memset(faceRemapInverse.get(), 0xff, sizeof(uint32_t) * nFaces);

        assert(vertexCache >= restart);
        uint32_t desired = vertexCache - restart;

        for (const auto& it : subsets)
        {
            hr = status.setSubset(indices, nFaces, it.first, it.second);
            if (FAILED(hr))
                return hr;

            vcache.clear();

            uint32_t locnext = 0;
            facecorner_t nextCorner(UNUSED32, UNUSED32);
            facecorner_t curCorner(UNUSED32, UNUSED32);

            uint32_t curface = 0;

            for (;;)
            {
                assert(nextCorner.first == UNUSED32);

                curCorner.first = status.find_initial();
                if (curCorner.first == UNUSED32)
                    break;

                uint32_t n0 = status.get_neighbors(curCorner.first, 0);
                if ((n0 != UNUSED32) && !status.isprocessed(n0))
                {
                    curCorner.second = 1;
                }
                else
                {
                    uint32_t n1 = status.get_neighbors(curCorner.first, 1);
                    if ((n1 != UNUSED32) && !status.isprocessed(n1))
                    {
                        curCorner.second = 2;
                    }
                    else
                    {
                        curCorner.second = 0;
                    }
                }

                bool striprestart = false;
                for (;;)
                {
                    assert(curCorner.first != UNUSED32);
                    assert(!status.isprocessed(curCorner.first));

                    // Decision: either add a ring of faces or restart strip
                    if (nextCorner.first != UNUSED32)
                    {
                        uint32_t nf = 0;
                        for (facecorner_t temp = curCorner; ; )
                        {
                            facecorner_t next = counterclockwise_corner<index_t>(temp, status);
                            if ((next.first == UNUSED32) || status.isprocessed(next.first))
                                break;
                            ++nf;
                            temp = next;
                        }

                        if (locnext + nf > desired)
                        {
                            // restart
                            if (!status.isprocessed(nextCorner.first))
                            {
                                curCorner = nextCorner;
                            }

                            nextCorner.first = UNUSED32;
                        }
                    }

                    for (;;)
                    {
                        assert(curCorner.first != UNUSED32);
                        status.mark(curCorner.first);

                        faceRemapInverse[curCorner.first] = uint32_t(curface + it.first);
                        curface += 1;

                        assert(indices[curCorner.first * 3] != index_t(-1));
                        if (!vcache.access(indices[curCorner.first * 3]))
                            locnext += 1;

                        assert(indices[curCorner.first * 3 + 1] != index_t(-1));
                        if (!vcache.access(indices[curCorner.first * 3 + 1]))
                            locnext += 1;

                        assert(indices[curCorner.first * 3 + 2] != index_t(-1));
                        if (!vcache.access(indices[curCorner.first * 3 + 2]))
                            locnext += 1;

                        facecorner_t intCorner = counterclockwise_corner<index_t>(curCorner, status);
                        bool interiornei = (intCorner.first != UNUSED32) && !status.isprocessed(intCorner.first);

                        facecorner_t extCorner = counterclockwise_corner<index_t>(facecorner_t(curCorner.first, (curCorner.second + 2) % 3), status);
                        bool exteriornei = (extCorner.first != UNUSED32) && !status.isprocessed(extCorner.first);

                        if (interiornei)
                        {
                            if (exteriornei)
                            {
                                if (nextCorner.first == UNUSED32)
                                {
                                    nextCorner = extCorner;
                                    locnext = 0;
                                }
                            }
                            curCorner = intCorner;
                        }
                        else if (exteriornei)
                        {
                            curCorner = extCorner;
                            break;
                        }
                        else
                        {
                            curCorner = nextCorner;
                            nextCorner.first = UNUSED32;

                            if ((curCorner.first == UNUSED32) || status.isprocessed(curCorner.first))
                            {
                                striprestart = true;
                                break;
                            }
                        }
                    }

                    if (striprestart)
                        break;
                }
            }
        }

        // inverse remap
        memset(faceRemap, 0xff, sizeof(uint32_t) * nFaces);

        for (uint32_t j = 0; j < nFaces; ++j)
        {
            uint32_t f = faceRemapInverse[j];
            if (f < nFaces)
            {
                faceRemap[f] = j;
            }
        }

        return S_OK;
    }