in UVAtlas/isochart/packingcharts.cpp [1398:1647]
inline static HRESULT FindChartPosition(
PackingDirection direction,
ATLASINFO& atlasInfo,
PACKINGINFO* pPackingInfo,
size_t dwRotationID,
XMFLOAT2& resultOrg,
float& fBetweenArea,
float& fAreaLost)
{
VERTEX_ARRAY* pAtlasBorder = nullptr;
VERTEX_ARRAY* pChartBorder = nullptr;
Axis TangentAxis = YAxis;
Axis RadialAxis = XAxis;
// The radial coordinate of the border vertex in atlas, which is nearest to the new chart
float fAtlasNearChartExtreme = 0;
// The radial coordinate of the border vertex in atlas, which is farest to the new chart
float fAtlasAwayChartExtreme = 0;
// The largest tangent coordinate of the border vertex in atlas.
float fAtlasTangentMaxExtreme = 0;
// The smallest tangent coordinate of the border vertex in atlas.
float fAtlasTangentMinExtreme = 0;
float fChartTangentSize = 0;
float fChartRadialSize = 0;
bool bPackingFromLowerPlace = false;
VertexLocation invalidChartLocationAgainstAtlas;
VertexLocation invalidatlasLocationAgainstChart;
switch (direction)
{
case FromRight:
pAtlasBorder = &(atlasInfo.currentRightBorder);
pChartBorder = &(pPackingInfo->leftBorder[dwRotationID]);
fAtlasNearChartExtreme = atlasInfo.fBoxRight;
fAtlasAwayChartExtreme = atlasInfo.fBoxLeft;
fAtlasTangentMaxExtreme = atlasInfo.fBoxTop;
fAtlasTangentMinExtreme = atlasInfo.fBoxBottom;
fChartTangentSize = pPackingInfo->fUVHeight[dwRotationID];
fChartRadialSize = pPackingInfo->fUVWidth[dwRotationID];
invalidChartLocationAgainstAtlas = LeftToBorder;
invalidatlasLocationAgainstChart = RightToBorder;
break;
case FromLeft:
pAtlasBorder = &(atlasInfo.currentLeftBorder);
pChartBorder = &(pPackingInfo->rightBorder[dwRotationID]);
fAtlasNearChartExtreme = atlasInfo.fBoxLeft;
fAtlasAwayChartExtreme = atlasInfo.fBoxRight;
fAtlasTangentMaxExtreme = atlasInfo.fBoxTop;
fAtlasTangentMinExtreme = atlasInfo.fBoxBottom;
fChartTangentSize = pPackingInfo->fUVHeight[dwRotationID];
fChartRadialSize = pPackingInfo->fUVWidth[dwRotationID];
bPackingFromLowerPlace = true;
invalidChartLocationAgainstAtlas = RightToBorder;
invalidatlasLocationAgainstChart = LeftToBorder;
break;
case FromTop:
pAtlasBorder = &(atlasInfo.currentTopBorder);
pChartBorder = &(pPackingInfo->bottomBorder[dwRotationID]);
TangentAxis = XAxis; // x field
RadialAxis = YAxis;
fAtlasNearChartExtreme = atlasInfo.fBoxTop;
fAtlasAwayChartExtreme = atlasInfo.fBoxBottom;
fAtlasTangentMaxExtreme = atlasInfo.fBoxRight;
fAtlasTangentMinExtreme = atlasInfo.fBoxLeft;
fChartTangentSize = pPackingInfo->fUVWidth[dwRotationID];
fChartRadialSize = pPackingInfo->fUVHeight[dwRotationID];
invalidChartLocationAgainstAtlas = BelowBorder;
invalidatlasLocationAgainstChart = AboveBorder;
break;
case FromBottom:
pAtlasBorder = &(atlasInfo.currentBottomBorder);
pChartBorder = &(pPackingInfo->topBorder[dwRotationID]);
TangentAxis = XAxis; // x field
RadialAxis = YAxis;
fAtlasNearChartExtreme = atlasInfo.fBoxBottom;
fAtlasAwayChartExtreme = atlasInfo.fBoxTop;
fAtlasTangentMaxExtreme = atlasInfo.fBoxRight;
fAtlasTangentMinExtreme = atlasInfo.fBoxLeft;
fChartTangentSize = pPackingInfo->fUVWidth[dwRotationID];
fChartRadialSize = pPackingInfo->fUVHeight[dwRotationID];
bPackingFromLowerPlace = true;
invalidChartLocationAgainstAtlas = AboveBorder;
invalidatlasLocationAgainstChart = BelowBorder;
break;
default:
assert(false);
return E_FAIL;
}
VERTEX_ARRAY& atlasBorder = *pAtlasBorder;
VERTEX_ARRAY& chartBorder = *pChartBorder;
XMFLOAT2* pOrigUV = pPackingInfo->pStandardUV;
// Border is composite with virtual vertices
if (chartBorder[0]->dwIDInRootMesh == INVALID_VERT_ID)
{
pOrigUV = pPackingInfo->pStandardVirtualCorner;
}
float fMinAreaLost = FLT_MAX;
float fMiniBetweenArea = FLT_MAX;
fAreaLost = FLT_MAX;
float fMinTangentPosition = VECTOR_ITEM(&atlasBorder[0]->uv, TangentAxis);
// Decide the searching step length
float fTangentRange =
VECTOR_ITEM(&atlasBorder[atlasBorder.size() - 1]->uv, TangentAxis) -
VECTOR_ITEM(&atlasBorder[0]->uv, TangentAxis) - fChartTangentSize;
size_t dwTangentLenInPixel;
if (fTangentRange < 0)
{
dwTangentLenInPixel = 1;
}
else
{
dwTangentLenInPixel =
static_cast<size_t>(fTangentRange / atlasInfo.fPixelLength) + 1;
}
size_t dwStepLength = GetSearchStepLength(dwTangentLenInPixel);
ISOCHARTVERTEX startExtraVertex, endExtraVertex;
// To guarantee enough gutter between different charts, add 2 extra vertex
// at each end of current chart border.
VERTEX_ARRAY newChartBorder;
try
{
newChartBorder.push_back(&startExtraVertex);
newChartBorder.insert(newChartBorder.end(), chartBorder.cbegin(), chartBorder.cend());
newChartBorder.push_back(&endExtraVertex);
}
catch (std::bad_alloc&)
{
return E_OUTOFMEMORY;
}
// Put current chart far away atlas, by fRadialDelta offset
float fRadialDelta;
if (bPackingFromLowerPlace)
{
fRadialDelta =
fAtlasNearChartExtreme - fChartRadialSize - 100 * atlasInfo.fGutter;
}
else
{
fRadialDelta =
fAtlasNearChartExtreme + fChartRadialSize + 100 * atlasInfo.fGutter;
}
// Search the optimal packing position
for (size_t i = 0; i < dwTangentLenInPixel; i += dwStepLength)
{
fBetweenArea = 0;
// Searching from center to both sides
float fTangentDelta;
if (dwTangentLenInPixel > 1)
{
fTangentDelta =
fMinTangentPosition + float((i + dwTangentLenInPixel / 2) % dwTangentLenInPixel)
* fTangentRange / float(dwTangentLenInPixel - 1);
}
else
{
fTangentDelta = fMinTangentPosition;
}
// Move chart to new position
MoveChartToNewPosition(
newChartBorder,
pOrigUV,
TangentAxis,
RadialAxis,
fTangentDelta,
fRadialDelta,
atlasInfo.fGutter);
// Find correspond segments on atlas border and chart border
size_t atlasBorderStart, atlasBorderEnd;
size_t newChartBorderStart, newChartBorderEnd;
if (!FindCorrespondSegmentsOfBorders(
atlasBorder,
newChartBorder,
atlasBorderStart,
atlasBorderEnd,
newChartBorderStart,
newChartBorderEnd,
TangentAxis))
{
continue;
}
// Calculate the minimal distance between chart and atlas
float fMinDistance = FLT_MAX;
if (!CalMinDistanceBetweenAtlasAndChart(
invalidatlasLocationAgainstChart,
invalidChartLocationAgainstAtlas,
bPackingFromLowerPlace,
newChartBorder,
newChartBorderStart,
newChartBorderEnd,
atlasBorder,
atlasBorderStart,
atlasBorderEnd,
TangentAxis,
RadialAxis,
atlasInfo.fGutter,
fMinDistance,
fBetweenArea))
{
continue;
}
// Move chart from far away position to the real packing position. Check if current
// position is better than old ones
UpdateOptimalPosition(
bPackingFromLowerPlace,
atlasInfo,
atlasBorder,
fAtlasNearChartExtreme,
fAtlasAwayChartExtreme,
fAtlasTangentMaxExtreme,
fAtlasTangentMinExtreme,
TangentAxis,
RadialAxis,
fChartTangentSize,
fChartRadialSize,
fTangentDelta,
fRadialDelta,
fMinDistance,
fBetweenArea,
resultOrg,
fMinAreaLost,
fMiniBetweenArea);
}
fBetweenArea = fMiniBetweenArea;
fAreaLost = fMinAreaLost;
return S_OK;
}