HRESULT CIsochartMesh::PackingOneChart()

in UVAtlas/isochart/packingcharts.cpp [2504:2798]


HRESULT CIsochartMesh::PackingOneChart(
    CIsochartMesh* pChart,
    ATLASINFO& atlasInfo,
    size_t dwIteration)
{
    HRESULT hr = S_OK;

    auto pPackingInfo = pChart->GetPackingInfoBuffer();

    // 1.  If current chart's area is zero, don't pack it, just put it at (0, 0).
    if (IsInZeroRange2(pChart->m_fChart2DArea))
    {
        PackingZeroAreaChart(pChart);
        return hr;
    }
    // 2. Rotate current chart and Calculate the borders of the chart in all directions
    // This function rotate current chart in CHART_ROTATION_NUMBER direction, Calculate
    // left, right, top and bottom borders of in each direction. Calculate bounding box
    // of current chart in each direction.
    FAILURE_RETURN(pChart->CalculateChartBordersOfAllDirection(atlasInfo));

    // 3. Packing one chart
    size_t dwMinRotationId = 0;
    size_t dwDirMinRotationId[PACKING_DIRECTION_NUMBER];

    float fAreaLost = 0;
    float fMinAreaLost = 0;
    float fDirMinAreaLost[PACKING_DIRECTION_NUMBER];

    float fBetweenArea;
    float fMinBetweenArea[PACKING_DIRECTION_NUMBER];

    XMFLOAT2 dirOrg[PACKING_DIRECTION_NUMBER];
    XMFLOAT2 newOrgin;

    /*
    //if ((dwIteration > 0 && dwIteration < 12) ||dwIteration > 12 )

    if (dwIteration > 1 )
    {
        for (size_t i=0; i<pChart->m_dwVertNumber; i++)
        {
            pChart->m_pVerts[i].uv.x = pChart->m_pVerts[i].uv.y = 0;
        }

        return hr;
    }
    */

    // 3.1 If current chart is the first chart to be packed,
    // initialize the UV-atlas by putting the first chart into it.
    if (0 == dwIteration || atlasInfo.fPackedChartArea == 0)
    {
        // Find one direction with smallest area lost rate.
        atlasInfo.fPackedChartArea = pChart->m_fChart2DArea;
        fMinAreaLost = FLT_MAX;
        for (size_t i = 0; i < CHART_ROTATION_NUMBER; i++)
        {
            fAreaLost =
                1.0f - atlasInfo.fPackedChartArea /
                (pPackingInfo->fUVWidth[i] * pPackingInfo->fUVHeight[i]);

            if (fAreaLost < fMinAreaLost)
            {
                fMinAreaLost = fAreaLost;
                dwMinRotationId = i;
            }
        }
        // Rotate chart to the direction gotten by above step
        pChart->RotateChartAroundCenter(dwMinRotationId, false);

        // Initialize atlas after packing the first chart.
        FAILURE_RETURN(
            Initializeatlas(
                atlasInfo,
                *pPackingInfo,
                dwMinRotationId));
    }

    // 3.2 Add charts into current atlas
    else
    {
        ISOCHARTVERTEX* pVex;

        atlasInfo.fPackedChartArea += pChart->m_fChart2DArea;

        for (size_t i = 0; i < PACKING_DIRECTION_NUMBER; i++)
        {
            fDirMinAreaLost[i] = FLT_MAX;
            fMinBetweenArea[i] = FLT_MAX;
            dwDirMinRotationId[i] = INVALID_INDEX;
        }

        atlasInfo.fExpectedAtlasWidth =
            (atlasInfo.fBoxTop - atlasInfo.fBoxBottom) * atlasInfo.fWidthHeightRatio;

        // 3.1.1 Need to add chart in horizon direction to increase width of atlas
        if (atlasInfo.fExpectedAtlasWidth
        > atlasInfo.fBoxRight - atlasInfo.fBoxLeft)
        {
            for (size_t i = 0; i < CHART_ROTATION_NUMBER; i++)
            {
                ISOCHARTVERTEX* pOneBorderVertex = pPackingInfo->leftBorder[i][1];
                if (INVALID_VERT_ID == pOneBorderVertex->dwIDInRootMesh)
                {
                    for (size_t j = 0; j < 4; j++)
                    {
                        pPackingInfo->pStandardVirtualCorner[j] = pOneBorderVertex[j].uv;
                    }
                }
                else
                {
                    pChart->RotateBordersAroundCenter(i);
                    pVex = pChart->GetVertexBuffer();
                    for (size_t j = 0; j < pChart->GetVertexNumber(); j++)
                    {
                        pPackingInfo->pStandardUV[j] = pVex->uv;
                        pVex++;
                    }
                }

                //Try packing from right
                FAILURE_RETURN(
                    FindChartPosition(
                        FromRight,
                        atlasInfo,
                        pPackingInfo,
                        i,
                        newOrgin,
                        fBetweenArea,
                        fAreaLost));

                UpdateAreaLostInfo(
                    FromRight,
                    dwDirMinRotationId,
                    i,
                    dirOrg,
                    newOrgin,
                    fDirMinAreaLost,
                    fAreaLost,
                    fMinBetweenArea,
                    fBetweenArea);

                //Try packing from left
                FAILURE_RETURN(
                    FindChartPosition(
                        FromLeft,
                        atlasInfo,
                        pPackingInfo,
                        i,
                        newOrgin,
                        fBetweenArea,
                        fAreaLost));

                UpdateAreaLostInfo(
                    FromLeft,
                    dwDirMinRotationId,
                    i,
                    dirOrg,
                    newOrgin,
                    fDirMinAreaLost,
                    fAreaLost,
                    fMinBetweenArea,
                    fBetweenArea);
            }
        }

        // 3.1.2 Need to add chart in vertical direction to increase height of atlas
        else
        {
            for (size_t i = 0; i < CHART_ROTATION_NUMBER; i++)
            {
                ISOCHARTVERTEX* pOneBorderVertex = pPackingInfo->topBorder[i][1];
                if (INVALID_VERT_ID == pOneBorderVertex->dwIDInRootMesh)
                {
                    for (size_t j = 0; j < 4; j++)
                    {
                        pPackingInfo->pStandardVirtualCorner[j] = pOneBorderVertex[j].uv;
                    }
                }
                else
                {
                    pChart->RotateBordersAroundCenter(i);
                    pVex = pChart->GetVertexBuffer();
                    for (size_t j = 0; j < pChart->GetVertexNumber(); j++)
                    {
                        pPackingInfo->pStandardUV[j] = pVex->uv;
                        pVex++;
                    }
                }

                //Try packing from top
                FAILURE_RETURN(
                    FindChartPosition(
                        FromTop,
                        atlasInfo,
                        pPackingInfo,
                        i,
                        newOrgin,
                        fBetweenArea,
                        fAreaLost));

                UpdateAreaLostInfo(
                    FromTop,
                    dwDirMinRotationId,
                    i,
                    dirOrg,
                    newOrgin,
                    fDirMinAreaLost,
                    fAreaLost,
                    fMinBetweenArea,
                    fBetweenArea);

                //Try packing from bottom
                FAILURE_RETURN(
                    FindChartPosition(
                        FromBottom,
                        atlasInfo,
                        pPackingInfo,
                        i,
                        newOrgin,
                        fBetweenArea,
                        fAreaLost));

                UpdateAreaLostInfo(
                    FromBottom,
                    dwDirMinRotationId,
                    i,
                    dirOrg,
                    newOrgin,
                    fDirMinAreaLost,
                    fAreaLost,
                    fMinBetweenArea,
                    fBetweenArea);
            }
        }

        // 3.2 Find the approach which causes less area lost
        size_t dwPackDirection = FromRight;
        for (size_t j = 1; j < PACKING_DIRECTION_NUMBER; j++)
        {
            if (fDirMinAreaLost[j] < fDirMinAreaLost[dwPackDirection])
            {
                dwPackDirection = j;
            }
        }

        if (dwDirMinRotationId[dwPackDirection] == INVALID_INDEX)
        {
            DPF(0, "2d area %f", double(pChart->m_fChart2DArea));
            DPF(0, "3d area %f", double(pChart->m_fChart3DArea));
            DPF(0, "Face number %zu", pChart->m_dwFaceNumber);
            DPF(0, "Vert number %zu", pChart->m_dwVertNumber);

            for (size_t ii = 0; ii < pChart->m_dwVertNumber; ii++)
            {
                DPF(0, "(%f, %f)", double(pChart->m_pVerts[ii].uv.x), double(pChart->m_pVerts[ii].uv.y));
            }
        }

        assert(dwDirMinRotationId[dwPackDirection] != INVALID_INDEX);

        // 3.3 Use the method gotten by last step to pack current chart
        pChart->RotateChartAroundCenter(dwDirMinRotationId[dwPackDirection], false);
        newOrgin = dirOrg[dwPackDirection];
        pVex = pChart->GetVertexBuffer();
        for (size_t i = 0; i < pChart->GetVertexNumber(); i++)
        {
            pVex->uv.x += newOrgin.x;
            pVex->uv.y += newOrgin.y;
            pVex++;
        }

        ISOCHARTVERTEX* pOneBorderVertex
            = pPackingInfo->leftBorder[dwDirMinRotationId[dwPackDirection]][1];
        if (INVALID_VERT_ID == pOneBorderVertex->dwIDInRootMesh)
        {
            pVex = pChart->GetVertexBuffer();
            AdjustCornerBorder(
                pOneBorderVertex,
                pVex,
                pChart->GetVertexNumber());
        }

        // 3.4 Update current horizon lines.
        FAILURE_RETURN(
            UpdateAtlas(
                atlasInfo,
                *pPackingInfo,
                newOrgin,
                dwDirMinRotationId[dwPackDirection]));
    }

    return hr;
}