JD2022-TU1/main/tools/legacy/TexturePacker/AnimTexPacker/PackingTexture.cpp

654 lines
No EOL
19 KiB
C++

#include "stdafx.h"
#ifndef _PACKING_TEXTURE_H_
#include "AnimTexPacker/PackingTexture.h"
#endif //_PACKING_TEXTURE_H_
#include "TexturePacker\PackerLog.h"
#ifndef _ITF_ANIMTEXPACKER_PATCH_H_
#include "AnimTexPacker/Patch.h"
#endif
namespace ITF
{
//*****************************************************************************
PackingTexture::PackingTexture(const ListPatch & _patchs, u32 _width, u32 _height, f32 _sampling)
: m_patchs(_patchs)
, m_width(_width)
, m_height(_height)
, m_gridSample(_sampling)
{
// Init grid
const u32 countColRow = m_width * m_height;
m_grid.resize(countColRow);
for (u32 i = 0; i < countColRow; i++)
{
m_grid[i] = 1;
}
}
//*****************************************************************************
PackingTexture::~PackingTexture()
{
// none
}
//*****************************************************************************
void PackingTexture::reset( const ListPatch & _patchs, u32 _width, u32 _height, f32 _sampling )
{
m_patchs = _patchs;
m_width = _width;
m_height = _height;
m_gridSample = _sampling;
const u32 countColRow = m_width * m_height;
m_grid.resize(countColRow);
for (u32 i = 0; i < countColRow; i++)
{
m_grid[i] = 1;
}
}
int patchCompare(const void * _A, const void * _B)
{
const f32 areaA = ((PackingPatch *)_A)->m_area;
const f32 areaB = ((PackingPatch *)_B)->m_area;
return (int)(areaB - areaA);
//const PackingPatch *A = (PackingPatch *)_A;
//const PackingPatch *B = (PackingPatch *)_B;
//i32 AlenMax = A->m_heightSampling > A->m_widthSampling ? (int)A->m_heightSampling : (int)A->m_widthSampling;
//i32 BlenMax = B->m_heightSampling > B->m_widthSampling ? (int)B->m_heightSampling : (int)B->m_widthSampling;
//if (AlenMax != BlenMax)
// return BlenMax - AlenMax;
//i32 AlenMin = A->m_heightSampling < A->m_widthSampling ? (int)A->m_heightSampling : (int)A->m_widthSampling;
//i32 BlenMin = B->m_heightSampling < B->m_widthSampling ? (int)B->m_heightSampling : (int)B->m_widthSampling;
//return BlenMin - AlenMin;
}
//*****************************************************************************
//*****************************************************************************
bbool PackingTexture::packingPatch()
{
const u32 countPatchs = m_patchs.size();
const u32 countRow = m_height;
const u32 countCol = m_width;
if (m_minNeededGridElemts > countRow*countCol)
return bfalse;
TexturePacker::PackerLog::s_main->resetProgressbar(countPatchs);
#ifdef USE_NEW_GRID_COMPUTATION_SYSTEM
ITF_VECTOR<GridInfo> baseGrid;
baseGrid.reserve(2*m_height + 2*m_width);
for (u32 i=0; i<m_width; i++)
{
baseGrid.push_back(GridInfo(i, 0, s_gridComputationValue));
baseGrid.push_back(GridInfo(i, m_height-1, s_gridComputationValue));
}
for (u32 i=0; i<m_height; i++)
{
baseGrid.push_back(GridInfo(0, i, s_gridComputationValue));
baseGrid.push_back(GridInfo(m_width-1, i, s_gridComputationValue));
}
propagateGridValues(baseGrid);
#endif
for (u32 i = 0; i < countPatchs; i++)
{
bbool isPush = bfalse;
PackingPatch& patch = m_patchs[i];
i32 countMaxNeighbor = -1;
u32 bestX = 0;
u32 bestY = 0;
u32 bestModeRotate = ROTATE_0;
for (u32 mode = ROTATE_0; mode < ROTATE_COUNT; mode++ )
{
for(u32 indexRow = 0;indexRow < countRow; indexRow++)
{
for(u32 indexCol = 0; indexCol < countCol; indexCol++)
{
u32 countNeighbor;
if (isFree(patch, indexRow, indexCol, patch.m_widthSampling, patch.m_heightSampling, countNeighbor, mode))
{
if (countMaxNeighbor == -1 || (i32)countNeighbor > countMaxNeighbor)
{
countMaxNeighbor = countNeighbor;
bestX = indexCol;
bestY = indexRow;
bestModeRotate = mode;
}
isPush = btrue;
}
}
}
}
if (!isPush)
{
return bfalse;
}
else
{
pushPatch(bestY, bestX, bestModeRotate, patch);
}
TexturePacker::PackerLog::s_main->progressbarStep();
}
return btrue;
}
//*****************************************************************************
void PackingTexture::growTexture()
{
if (m_width <= m_height)
m_width *= 2;
else
m_height *= 2;
u32 newSize = m_width * m_height;
m_grid.resize(newSize);
for (u32 i = 0; i < newSize; i++)
{
m_grid[i] = 1;
}
countGrow++;
}
//*****************************************************************************
void PackingTexture::pushPatch(u32 _indexRow, u32 _indexCol, u32 _mode, PackingPatch& _patch)
{
_patch.m_rotateMode = _mode;
// Move patch
Vec2d posInGrid = Vec2d(_indexCol * m_gridSample, _indexRow * m_gridSample);
Vec2d vecMove = posInGrid - _patch.m_obb.getMin();
_patch.m_translation = posInGrid;
const u32 countPoints = _patch.m_points.size();
for (u32 j = 0; j < countPoints; j++)
{
Vec2d& point = _patch.m_points[j]; // Ref
point += vecMove;
}
_patch.m_obb.moveCenter(_patch.m_obb.getCenter() + vecMove);
_patch.m_baryCenter += vecMove;
_patch.m_posInImage = posInGrid;
// Update Grid
u32 countColPatch = _patch.m_widthSampling;
u32 countRowPatch = _patch.m_heightSampling;
switch(_mode)
{
case ROTATE_0:
_patch.m_rotation = _patch.m_angle;
break;
case ROTATE_180:
_patch.m_rotation = _patch.m_angle + MTH_PI;
break;
case ROTATE_90:
_patch.m_rotation = _patch.m_angle - MTH_PIBY2;
countColPatch = _patch.m_heightSampling;
countRowPatch = _patch.m_widthSampling;
break;
case ROTATE_270:
_patch.m_rotation = _patch.m_angle + MTH_PIBY2;
countColPatch = _patch.m_heightSampling;
countRowPatch = _patch.m_widthSampling;
break;
}
const u32 countCol = m_width;
u32 indexRowPatch = 0;
ITF_VECTOR<GridInfo> gridInfo;
for(u32 indexRow = _indexRow; indexRow < _indexRow + countRowPatch; indexRow++)
{
u32 indexColPatch = 0;
for(u32 indexCol = _indexCol; indexCol < _indexCol + countColPatch; indexCol++)
{
const u32 index = indexRow * countCol + indexCol;
//const u32 indexPatch = indexRowPatch * _patch.m_widthSampling + indexColPatch;
u32 indexPatch = 0;
switch(_mode)
{
case ROTATE_0:
indexPatch = indexRowPatch * countColPatch + indexColPatch;
break;
case ROTATE_90:
indexPatch = (countRowPatch - indexRowPatch - 1) + (indexColPatch * countRowPatch);
break;
case ROTATE_180:
indexPatch = ((countRowPatch - indexRowPatch - 1) * countColPatch) + (countColPatch - indexColPatch - 1);
break;
case ROTATE_270:
indexPatch = (indexRowPatch) + ((countColPatch - indexColPatch - 1) * countRowPatch);
break;
}
if (_patch.m_sampling[indexPatch] > 0)
{
#ifdef USE_NEW_GRID_COMPUTATION_SYSTEM
gridInfo.push_back(GridInfo(indexCol, indexRow, 0));
#else
m_grid[index] = 0;
#endif
}
indexColPatch++;
}
indexRowPatch++;
}
#ifdef USE_NEW_GRID_COMPUTATION_SYSTEM
propagateGridValues(gridInfo);
#endif
}
//*****************************************************************************
#ifdef USE_NEW_GRID_COMPUTATION_SYSTEM
i32 getEmptyIndex(GridInfo* & _grid, SafeArray<GridInfo> & _gridIndexes, u32 & _begin, u32 & _end, i32 & _nbInList, u32 & _gridSize)
{
i32 returnVal;
if (_nbInList >= (i32)_gridSize-1)
{
_gridIndexes.resize(_gridSize*2);
for (u32 i=0; i<_end; i++)
{
_gridIndexes[_gridSize + i] = _gridIndexes[i];
}
_end += _gridSize - 1;
_gridSize = _gridIndexes.size();
_grid = &_gridIndexes[_begin];
}
returnVal = _end;
_end = (_end + 1) % _gridSize;
_nbInList++;
return returnVal;
}
void PackingTexture::propagateGridValues(const ITF_VECTOR<GridInfo> & _gridIndexes)
{
u32 beginBuffer = 0;
u32 endBuffer = 0;
u32 sizeBuffer = m_grid.size();
m_gridInfoTMP.resize(sizeBuffer);
i32 nbInList = 0;
GridInfo * grid = &m_gridInfoTMP[0];
for (ITF_VECTOR<GridInfo>::const_iterator _gridIter = _gridIndexes.begin();
_gridIter != _gridIndexes.end(); _gridIter++)
{
m_gridInfoTMP[getEmptyIndex(grid, m_gridInfoTMP, beginBuffer, endBuffer, nbInList, sizeBuffer)] = *_gridIter;
}
while (beginBuffer != endBuffer)
{
// first set element
grid = &m_gridInfoTMP[beginBuffer];
i32 index = grid->m_x + grid->m_y*m_width;
if (m_grid[index] != 0 && m_grid[index] != grid->m_val && (!grid->m_val || grid->m_val > m_grid[index]))
{
m_grid[index] = grid->m_val;
i32 divVal = grid->m_val ? grid->m_val / 2 : s_gridComputationValue;
if (grid->m_x > 0)
{
i32 indexL = grid->m_x - 1 + grid->m_y*m_width;
if (m_grid[indexL] != 0 && m_grid[indexL] != divVal && divVal > m_grid[indexL])
{
m_gridInfoTMP[getEmptyIndex(grid, m_gridInfoTMP, beginBuffer, endBuffer, nbInList, sizeBuffer)] = GridInfo(grid->m_x - 1, grid->m_y, divVal);
}
}
if (grid->m_x < (i32)m_width - 1)
{
i32 indexR = grid->m_x + 1 + grid->m_y*m_width;
if (m_grid[indexR] != 0 && m_grid[indexR] != divVal && divVal > m_grid[indexR])
{
m_gridInfoTMP[getEmptyIndex(grid, m_gridInfoTMP, beginBuffer, endBuffer, nbInList, sizeBuffer)] = GridInfo(grid->m_x + 1, grid->m_y, divVal);
}
}
if (grid->m_y > 0)
{
i32 indexD = grid->m_x + (grid->m_y - 1)*m_width;
if (m_grid[indexD] != 0 && m_grid[indexD] != divVal && divVal > m_grid[indexD])
{
m_gridInfoTMP[getEmptyIndex(grid, m_gridInfoTMP, beginBuffer, endBuffer, nbInList, sizeBuffer)] = GridInfo(grid->m_x, grid->m_y - 1, divVal);
}
}
if (grid->m_y < (i32)m_height - 1)
{
i32 indexU = grid->m_x + (grid->m_y + 1)*m_width;
if (m_grid[indexU] != 0 && m_grid[indexU] != divVal && divVal > m_grid[indexU])
{
m_gridInfoTMP[getEmptyIndex(grid, m_gridInfoTMP, beginBuffer, endBuffer, nbInList, sizeBuffer)] = GridInfo(grid->m_x, grid->m_y + 1, divVal);
}
}
}
beginBuffer = (beginBuffer + 1) % sizeBuffer;
nbInList--;
}
}
#endif
bbool PackingTexture::isFree(PackingPatch& _patch, u32 _indexRow, u32 _indexCol, u32 _width, u32 _height, u32& _countNeighbor, u32 _mode)
{
const u32 countCol = m_width;
_countNeighbor = 0;
u32 countColPatch = _patch.m_widthSampling;
u32 countRowPatch = _patch.m_heightSampling;
switch(_mode)
{
case ROTATE_0:
case ROTATE_180:
break;
case ROTATE_90:
case ROTATE_270:
countColPatch = _patch.m_heightSampling;
countRowPatch = _patch.m_widthSampling;
break;
}
u32 indexRowPatch = 0;
if (_indexRow + countRowPatch > m_height || _indexCol + countColPatch > m_width)
{
return bfalse;
}
for(u32 indexRow = _indexRow; indexRow < _indexRow + countRowPatch; indexRow++)
{
u32 indexColPatch = 0;
for(u32 indexCol = _indexCol; indexCol < _indexCol + countColPatch; indexCol++)
{
const u32 index = indexRow * countCol + indexCol;
u32 indexPatch = 0;
switch(_mode)
{
case ROTATE_0:
indexPatch = indexRowPatch * countColPatch + indexColPatch;
break;
case ROTATE_90:
indexPatch = (countRowPatch - indexRowPatch - 1) + (indexColPatch * countRowPatch);
break;
case ROTATE_180:
indexPatch = ((countRowPatch - indexRowPatch - 1) * countColPatch) + (countColPatch - indexColPatch - 1);
break;
case ROTATE_270:
indexPatch = (indexRowPatch) + ((countColPatch - indexColPatch - 1) * countRowPatch);
break;
}
if (m_grid[index] == 0 && _patch.m_sampling[indexPatch] > 0)
{
return bfalse;
}
#ifdef USE_NEW_GRID_COMPUTATION_SYSTEM
if (_patch.m_sampling[indexPatch] > 0)
_countNeighbor += m_grid[index];
#else
u32 sampleValue = _patch.m_sampling[indexPatch];
if (((_patch.m_sampling[indexPatch] & SAMPLE_MASK) % 2) && !(_patch.m_sampling[indexPatch] & SAMPLE_TAG))
{
_countNeighbor += getCountNeighbor(indexRow, indexCol);
}
#endif
indexColPatch++;
}
indexRowPatch++;
}
return btrue;
}
//*****************************************************************************
#ifndef USE_NEW_GRID_COMPUTATION_SYSTEM
u32 PackingTexture::getCountNeighbor(u32 _indexRow, u32 _indexCol)
{
u32 res = 0;
u32 x, y;
u32 index;
// Top
if (_indexRow == m_height - 1)
{
res++;
}
else
{
x = _indexCol;
y = _indexRow + 1;
index = y * m_width + x;
if (!m_grid[index])
{
res++;
}
}
// Down
if (_indexRow == 0)
{
res++;
}
else
{
x = _indexCol;
y = _indexRow - 1;
index = y * m_width + x;
if (!m_grid[index])
{
res++;
}
}
// Left
if (_indexCol == 0)
{
res++;
}
else
{
x = _indexCol - 1;
y = _indexRow;
index = y * m_width + x;
if (!m_grid[index])
{
res++;
}
}
// Right
if (_indexCol == m_width - 1)
{
res++;
}
else
{
x = _indexCol + 1;
y = _indexRow;
index = y * m_width + x;
if (!m_grid[index])
{
res++;
}
}
return res;
}
#endif
//*****************************************************************************
void PackingTexture::computeGrid()
{
const u32 countPatchs = m_patchs.size();
if (!countPatchs)
return;
TexturePacker::PackerLog::s_main->resetProgressbar(countPatchs);
// Compute all OBB patch
m_minNeededGridElemts = 0;
m_maxNeededGridElemts = 0;
for (u32 i = 0; i < countPatchs; i++)
{
PackingPatch& patch = m_patchs[i];
patch.computeOBB();
patch.sample(m_gridSample);
u32 localGridSize = patch.m_widthSampling*patch.m_heightSampling;
m_maxNeededGridElemts += localGridSize;
for (u32 xy=0; xy<localGridSize; xy++)
m_minNeededGridElemts += patch.m_sampling[xy] ? 1 : 0;
TexturePacker::PackerLog::s_main->progressbarStep();
}
// Sort patch by area
qsort(&m_patchs[0],countPatchs, sizeof(PackingPatch), patchCompare);
while (m_minNeededGridElemts > m_height*m_width)
growTexture();
}
void PackingTexture::recomputeRotation(ListPatch & patchs)
{
// Update Grid
TexturePacker::PackerLog::s_main->resetProgressbar(patchs.size());
for (u32 patchIndex=0; patchIndex<patchs.size(); patchIndex++)
{
PackingPatch & packingPatch = patchs[patchIndex];
u32 countPoints = packingPatch.m_points.size();
u32 countColPatch = packingPatch.m_widthSampling;
u32 countRowPatch = packingPatch.m_heightSampling;
SafeArray<u32> newSampling = packingPatch.m_sampling;
// first do final changes
f32 angleMode = 0.0f;
AABB obbTemp = packingPatch.m_obb;
Vec2d center = Vec2d((f32)packingPatch.m_widthSampling*AnimTexPacker::PatchList::CURRENT_SAMPLING,
(f32)packingPatch.m_heightSampling*AnimTexPacker::PatchList::CURRENT_SAMPLING)*0.5f;
switch(packingPatch.m_rotateMode)
{
case ROTATE_0:
angleMode = 0.0f;
break;
case ROTATE_180:
angleMode = MTH_PI;
for (u32 y=0; y<packingPatch.m_heightSampling; y++)
for (u32 x=0; x<packingPatch.m_widthSampling; x++)
newSampling[(packingPatch.m_widthSampling-x-1)+(packingPatch.m_heightSampling - y - 1)*packingPatch.m_widthSampling] = packingPatch.m_sampling[x+y*packingPatch.m_widthSampling];
break;
case ROTATE_90:
{
countColPatch = packingPatch.m_heightSampling;
countRowPatch = packingPatch.m_widthSampling;
angleMode = -MTH_PIBY2;
f32 x = packingPatch.m_obb.getMin().x() + packingPatch.m_obb.getHeight();
f32 y = packingPatch.m_obb.getMin().y() + packingPatch.m_obb.getWidth();
obbTemp.setMax(Vec2d(x, y));
for (u32 y=0; y<packingPatch.m_heightSampling; y++)
for (u32 x=0; x<packingPatch.m_widthSampling; x++)
newSampling[y+(packingPatch.m_widthSampling-x-1)*packingPatch.m_heightSampling] = packingPatch.m_sampling[x+y*packingPatch.m_widthSampling];
}
break;
case ROTATE_270:
{
countColPatch = packingPatch.m_heightSampling;
countRowPatch = packingPatch.m_widthSampling;
angleMode = MTH_PIBY2;
f32 x = packingPatch.m_obb.getMin().x() + packingPatch.m_obb.getHeight();
f32 y = packingPatch.m_obb.getMin().y() + packingPatch.m_obb.getWidth();
obbTemp.setMax(Vec2d(x, y));
for (u32 y=0; y<packingPatch.m_heightSampling; y++)
for (u32 x=0; x<packingPatch.m_widthSampling; x++)
newSampling[(packingPatch.m_heightSampling - y - 1) + x*packingPatch.m_heightSampling] = packingPatch.m_sampling[x+y*packingPatch.m_widthSampling];
}
break;
}
Vec2d newCenter = Vec2d((f32)countColPatch*AnimTexPacker::PatchList::CURRENT_SAMPLING,
(f32)countRowPatch*AnimTexPacker::PatchList::CURRENT_SAMPLING)*0.5f;
Vec2d moveVect = newCenter - center;
center += packingPatch.m_obb.getMin();
for (u32 i = 0; i < countPoints; i++)
{
Vec2d point = packingPatch.m_points[i];
point = point.RotateAround(center, angleMode);
point += moveVect;
packingPatch.m_points[i] = point;
}
packingPatch.m_obb = obbTemp;
packingPatch.m_widthSampling = countColPatch;
packingPatch.m_heightSampling = countRowPatch;
packingPatch.m_sampling = newSampling;
TexturePacker::PackerLog::s_main->progressbarStep();
}
}
i32 PackingTexture::s_gridComputationValue = 1024;
}