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

1041 lines
42 KiB
C++

#include "stdafx.h"
#ifndef _ITF_PBKMERGER_H_
#include "AnimTexPacker/PbkMerger.h"
#endif
#ifndef _ITF_ANIMTEXPACKER_PATCH_H_
#include "AnimTexPacker/Patch.h"
#endif
#ifndef _ITF_ANIMATIONPATCHBANK_H_
#include "engine/animation/AnimationPatchBank.h"
#endif // _ITF_ANIMATIONPATCHBANK_H_
#ifndef _ITF_ERRORHANDLER_H_
#include "core/error/ErrorHandler.h"
#endif //_ITF_ERRORHANDLER_H_
#ifndef _ITF_ASSERTMANAGER_H_
#include "core/AssertManager.h"
#endif //_ITF_ASSERTMANAGER_H_
#ifndef _ITF_ANIMPACKERCONFIGURATION_H_
#include "AnimTexPacker/AnimPackerConfiguration.h"
#endif
#ifndef _ITF_FILESERVER_H_
#include "core/file/FileServer.h"
#endif //_ITF_FILESERVER_H_
#ifndef _ITF_FILEMANAGER_H_
#include "core/AdaptersInterfaces/FileManager.h"
#endif //_ITF_FILEMANAGER_H_
#ifndef _ITF_SOURCECONTROLADAPTER_H_
#include "engine/AdaptersInterfaces/SourceControlAdapter.h"
#endif // _ITF_SOURCECONTROLADAPTER_H_
#ifndef _ITF_PATCHDEPOT_H_
#include "AnimTexPacker/PatchDepot.h"
#endif
#ifndef _PACKING_TEXTURE_H_
#include "AnimTexPacker/PackingTexture.h"
#endif //_PACKING_TEXTURE_H_
#ifndef _ITF_SYSTEMADAPTER_
#include "core/AdaptersInterfaces/SystemAdapter.h"
#endif //_ITF_SYSTEMADAPTER_
#include "TexturePacker\PackerLog.h"
//#define _ONLY_SQUARE_TEXTURES
//#define SIMULATE_HD
namespace ITF
{
namespace AnimTexPacker
{
///////////////////////////////////////////////////////////////////////////////////////////
int getUpperPowerOf2(int x)
{
x -= 1;
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x + 1;
}
///////////////////////////////////////////////////////////////////////////////////////////
//for sorting map by area with qsort
int mapSizeComparator(const void *_p1, const void *_p2)
{
BoxI &b1=*(BoxI*)_p1;
BoxI &b2=*(BoxI*)_p2;
int a1 = b1.maxx*b1.maxy;
int a2 = b2.maxx*b2.maxy;
if (a1<a2)
return -1;
else if (a1==a2)
{
int aspect1 = abs(b1.maxx-b1.maxy);
int aspect2 = abs(b2.maxx-b2.maxy);
if (aspect1<aspect2)
return -1;
else if (aspect1==aspect2)
return 0;
return 1;
}
return 1;
}
//For sorting by perimeter with qsort
static int patchComparator(const void *_p1, const void *_p2)
{
Patch* patch1 = *(Patch**)_p1;
Patch* patch2 = *(Patch**)_p2;
int halfPerim1 = patch1->getSubImageWidth()+patch1->getSubImageHeight();
int halfPerim2 = patch2->getSubImageWidth()+patch2->getSubImageHeight();
if (halfPerim1<halfPerim2)
return 1;
else if (halfPerim1==halfPerim2)
return 0;
return -1;
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::buildSortedPatches(SafeArray<Patch*> &_sortedPatchList)
{
_sortedPatchList.reserve(500);
ITF_LIST<PatchList*>::iterator patchListIter;
for (patchListIter=m_listOfPatchLists.begin();
patchListIter!=m_listOfPatchLists.end();
patchListIter++)
{
PatchList *patchList = *patchListIter;
ITF_LIST<Patch*>::const_iterator patchIter;
for (patchIter=patchList->m_patches.begin();
patchIter!=patchList->m_patches.end();
patchIter++)
{
_sortedPatchList.push_back(*patchIter);
}
}
if (_sortedPatchList.size())
qsort(&_sortedPatchList[0], _sortedPatchList.size(), sizeof(_sortedPatchList[0]), patchComparator);
}
///////////////////////////////////////////////////////////////////////////////////////////
Patch *PbkMerger::findPatch(const StringID &_templateID)
{
ITF_LIST<PatchList*>::iterator patchListIter;
for (patchListIter=m_listOfPatchLists.begin();
patchListIter!=m_listOfPatchLists.end();
patchListIter++)
{
PatchList *patchList = *patchListIter;
ITF_LIST<Patch*>::iterator patchIter;
for (patchIter=patchList->m_patches.begin(); patchIter!=patchList->m_patches.end(); patchIter++)
{
Patch *patch = *patchIter;
if (patch->getTemplateID()==_templateID)
{
return patch;
}
}
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::computeFinalMapStartupSize(int &mapWidth, int &mapHeight, int &totalArea)
{
totalArea=0;
mapWidth = 8;
mapHeight = 8;
ITF_LIST<PatchList*>::iterator patchListIter;
for (patchListIter=m_listOfPatchLists.begin();
patchListIter!=m_listOfPatchLists.end();
patchListIter++)
{
PatchList *patchList = *patchListIter;
ITF_LIST<Patch*>::const_iterator patchIter;
for (patchIter=patchList->m_patches.begin();
patchIter!=patchList->m_patches.end();
patchIter++)
{
Patch *patch = *patchIter;
if (patch->getSourceOfAlias())
continue;
int w = patch->getSubImageWidth();
int h = patch->getSubImageHeight();
totalArea += w*h;
mapWidth = Max(mapWidth, w);
mapHeight = Max(mapHeight, h);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::createCompositePatchBank(PatchDepot *_patchDepot)
{
ITF_ASSERT(m_compositeAnimPatchBank==NULL);
ITF_LIST<PatchList*>::iterator patchListIter;
m_compositeAnimPatchBank = newAlloc(mId_Temporary, AnimPatchBank);
for (patchListIter=m_listOfPatchLists.begin(); patchListIter!=m_listOfPatchLists.end(); patchListIter++)
{
PatchList *patchList = *patchListIter;
AnimPatchBank * patchBank = patchList->m_patchBank;
for (u32 nameIndex=0; nameIndex<patchBank->m_NameToTemplate.size(); nameIndex++)
{
u32 key = patchBank->m_NameToTemplate.getKeyAt(nameIndex);
if (_patchDepot)
{
bbool isUsed = bfalse;
for (ITF_LIST<PatchList>::iterator pIt = _patchDepot->begin();
pIt != _patchDepot->end(); ++pIt)
{
PatchList & pList = *pIt;
if (find(pList.m_usedPatches.begin(), pList.m_usedPatches.end(), StringID(key)) != pList.m_usedPatches.end())
{
isUsed = btrue;
break;
}
}
if (!isUsed)
continue;
}
u32 templateInitialIndex = patchBank->m_NameToTemplate.getAt(nameIndex);
if(m_compositeAnimPatchBank->m_NameToTemplate.find(key)>=0)
{
#ifdef ITF_DEBUG_STRINGID
const String8& debugStr = patchBank->m_NameToTemplate.getDebugAt(nameIndex);
LOG("2 patch banks contain templates %s\nOne of then will be trashed", debugStr.cStr());
#else
LOG("2 patch banks have templates with the same name - One of then will be trashed");
#endif
}
u32 templateMergedIndex=m_compositeAnimPatchBank->m_templateList.size();
#ifdef ITF_DEBUG_STRINGID
const String8& debugStr = patchBank->m_NameToTemplate.getDebugAt(nameIndex);
m_compositeAnimPatchBank->m_NameToTemplate.setDBG(key, templateMergedIndex, debugStr);
#else
m_compositeAnimPatchBank->m_NameToTemplate.set(key, templateMergedIndex);
#endif
m_compositeAnimPatchBank->m_templateList.push_back(patchBank->m_templateList[templateInitialIndex]);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::destroyCompositePatchBank()
{
//Actual templates will be freed by the patch depot, so we empty the values before destroying
//to avoid freeing memory twice
if (m_compositeAnimPatchBank)
m_compositeAnimPatchBank->m_templateList.clear();
SF_DEL(m_compositeAnimPatchBank);
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::buildSortedMapSizes(SafeArray<BoxI> &_sortedMapSizes, int mapWidth/*must be pow of 2*/, int mapHeight, int maxUV)
{
_sortedMapSizes.resize(0);
_sortedMapSizes.reserve(16);
for (int v=mapHeight/2; v<=maxUV; v*=2)
{
for (int u=mapWidth/2; u<=maxUV; u*=2)
{
BoxI dim(0,0,u,v);
_sortedMapSizes.push_back(dim);
}
}
if (_sortedMapSizes.size())
qsort(&_sortedMapSizes[0], _sortedMapSizes.size(), sizeof(_sortedMapSizes[0]), mapSizeComparator);
}
///////////////////////////////////////////////////////////////////////////////////////////
void PbkMerger::blitFinalImage(nv::Image &newImage, int offsetX, int offsetY, const SafeArray<Patch*> &_inputPatchList, u32 _textureId)
{
TexturePacker::PackerLog::s_main->resetProgressbar(_inputPatchList.size());
for (u32 patchIndex=0; patchIndex<_inputPatchList.size(); patchIndex++)
{
Patch *patch = _inputPatchList[patchIndex];
if (!patch->getSourceOfAlias())
patch->blitToFinalPos(newImage, offsetX, offsetY, (TextureSetSubID)_textureId);
TexturePacker::PackerLog::s_main->progressbarStep();
}
}
void PbkMerger::blitFinalImageData(int mapWidth, int mapHeight, const SafeArray<Patch*> &_inputPatchList)
{
ITF_SET<AnimPatchPoint*> alreadyProcessedPoints;
TexturePacker::PackerLog::s_main->resetProgressbar(_inputPatchList.size());
for (u32 patchIndex=0; patchIndex<_inputPatchList.size(); patchIndex++)
{
Patch *patch = _inputPatchList[patchIndex];
patch->modifyUVs(mapWidth, mapHeight, alreadyProcessedPoints);
TexturePacker::PackerLog::s_main->progressbarStep();
}
SafeArray<AnimTemplate *> templateList;
templateList.reserve(_inputPatchList.size());
for (u32 patchIndex=0; patchIndex<_inputPatchList.size(); patchIndex++)
{
Patch *patch = _inputPatchList[patchIndex];
AnimTemplate *tmplt = patch->getAnimTemplate();
if (templateList.find(tmplt) >= 0)
continue;
templateList.push_back(tmplt);
tmplt->ComputeBonesLocalPos(btrue);
}
}
PackingPatch * createPackingPatchFromPatch(Patch *_patch, f32 _surface, u32 & _sampleSize)
{
if (!_patch->getPointList().size())
return NULL;
BeginEnd be;
PackingPatch *packPatch = newAlloc(mId_System, PackingPatch());
packPatch->m_points = _patch->getPointList();
be.m_begin = 0;
be.m_end = packPatch->m_points.size()-1;
packPatch->m_subPoly.push_back(be);
// Results
packPatch->computeOBB(btrue);
packPatch->sample((f32)PatchList::CURRENT_SAMPLING);
u32 nbSample = packPatch->m_widthSampling*packPatch->m_heightSampling;
_sampleSize = 0;
for (u32 xy=0; xy<nbSample; xy++)
_sampleSize += packPatch->m_sampling[xy] ? 1 : 0;
return packPatch;
}
#define LIMIT_ONE 2
#define LIMIT_TWO 130 / 100
void fillPackFromPatches(ListPatch & _initPatchs, const SafeArray<Patch*> _sortedPatchList)
{
// First check for common AABB patches
BoxI resultBox;
KeyArray<SafeArray<u32>> processedMap;
SafeArray<u32> processedList;
PackingPatch *iPackPatch = NULL;
u32 iPackPatchSize = 0;
PackingPatch *jPackPatch = NULL;
u32 jPackPatchSize = 0;
// First Check if 2 patches have same name on different images
for (u32 i=0; i<_sortedPatchList.size(); i++)
{
Patch * patchI = _sortedPatchList[i];
for (u32 j=i+1; j<_sortedPatchList.size(); j++)
{
Patch * patchJ = _sortedPatchList[j];
if (patchI->getImagePath() != patchJ->getImagePath() &&
patchI->getTemplateID() == patchJ->getTemplateID())
{
String8 imgI, imgJ;
patchI->getImagePath().toString8(imgI);
patchJ->getImagePath().toString8(imgJ);
String8 tmpName = patchI->getTemplateID().getDebugString();
String8 msg;
msg.setTextFormat("Error !!\nTwo different images:\n-%s\n%s\nhave same patch name %s",
imgI.cStr(), imgJ.cStr(), tmpName.cStr());
SYSTEM_ADAPTER->messageBox(String8("Texture Packer"), msg, 64, ITF_IDYES);
exit(0);
}
}
}
for (u32 i=0; i<_sortedPatchList.size(); i++)
{
Patch * patchI = _sortedPatchList[i];
if (patchI->getSourceOfAlias())
continue;
if (processedList.find(i) >= 0)
continue;
for (u32 j=i+1; j<_sortedPatchList.size(); j++)
{
Patch * patchJ = _sortedPatchList[j];
if (patchJ->getSourceOfAlias())
continue;
if (patchI->getImagePath() != patchJ->getImagePath())
continue;
// First check for intersection
if (!patchI->getUVBox().intersect(patchJ->getUVBox(), resultBox))
continue;
int iSurf = patchI->getUVBox().surface();
int jSurf = patchJ->getUVBox().surface();
int rSurf = resultBox.surface();
// Second be sure that the intersect section is big enough
if (rSurf*LIMIT_ONE < iSurf && rSurf*LIMIT_ONE < jSurf)
continue;
// Optional - because costly
if (!iPackPatch)
{
iPackPatch = createPackingPatchFromPatch(patchI, (f32)iSurf, iPackPatchSize);
if (!iPackPatch)
continue;
}
jPackPatch = createPackingPatchFromPatch(patchJ, (f32)jSurf, jPackPatchSize);
if (!jPackPatch)
continue;
i32 xDelta = (i32)(f32(patchI->getUVBox().minx - patchJ->getUVBox().minx)/f32(PatchList::CURRENT_SAMPLING) + 0.5f);
i32 yDelta = (i32)(f32(patchI->getUVBox().miny - patchJ->getUVBox().miny)/f32(PatchList::CURRENT_SAMPLING) + 0.5f);
u32 rPackPatchSize = 0;
for (i32 y=0; y<(i32)iPackPatch->m_heightSampling; y++)
{
for (i32 x=0; x<(i32)iPackPatch->m_widthSampling; x++)
{
u32 idx = x + y*iPackPatch->m_widthSampling;
if (iPackPatch->m_sampling[idx])
{
i32 xDeltaIn = x + xDelta;
i32 yDeltaIn = y + yDelta;
if (xDeltaIn >= 0 && xDeltaIn < (i32)jPackPatch->m_widthSampling &&
yDeltaIn >= 0 && yDeltaIn < (i32)jPackPatch->m_heightSampling)
{
u32 idxDst = xDeltaIn + yDeltaIn*jPackPatch->m_widthSampling;
rPackPatchSize += jPackPatch->m_sampling[idxDst] ? 1 : 0;
}
}
}
}
SF_DEL(jPackPatch);
if (rPackPatchSize*LIMIT_TWO < iPackPatchSize && rPackPatchSize*LIMIT_TWO < jPackPatchSize)
continue;
i32 idx = processedMap.find(i);
if (idx >= 0)
{
SafeArray<u32> &childs = processedMap.getAt(idx);
childs.push_back(j);
} else
{
SafeArray<u32> childs;
childs.push_back(i);
childs.push_back(j);
processedMap.set(i, childs);
processedList.push_back(i);
}
processedList.push_back(j);
}
SF_DEL(iPackPatch);
}
BeginEnd be;
for (u32 i=0; i<processedMap.size(); i++)
{
SafeArray<u32> & childs = processedMap.getAt(i);
PackingPatch paaa;
for (u32 j=0; j<childs.size(); j++)
{
const ITF_VECTOR<Vec2d> & points = _sortedPatchList[childs[j]]->getPointList();
if (points.size())
{
be.m_begin = paaa.m_points.size();
be.m_end = be.m_begin+points.size()-1;
for (u32 k=0; k<points.size(); k++)
paaa.m_points.push_back(points[k]);
paaa.m_subPoly.push_back(be);
paaa.m_srcData.push_back(childs[j]);
}
}
if (paaa.m_subPoly.size())
_initPatchs.push_back(paaa);
}
for (u32 i=0; i<_sortedPatchList.size(); i++)
{
Patch * patchI = _sortedPatchList[i];
if (patchI->getSourceOfAlias())
continue;
if (processedList.find(i) >= 0 || !patchI->getPointList().size())
continue;
PackingPatch paaa;
paaa.m_points = patchI->getPointList();
be.m_begin = 0;
be.m_end = paaa.m_points.size()-1;
paaa.m_subPoly.push_back(be);
paaa.m_srcData.push_back(i);
_initPatchs.push_back(paaa);
}
}
/////// IMAGE Resize Cf Philippe VIMONT
bbool Reduce(nv::Image & MapSRC,nv::Image & MapDST)
{
if (MapSRC.width() < MapDST.width())
return bfalse;
nv::Color32 LineMerg1[16384];
i32 PosY,LastPosY;
nv::Color32 *LAST,*DST,*SRC;
LastPosY = -1;
for (u32 SizeY = 0; SizeY < MapSRC.height();SizeY ++)
{
DST = LineMerg1;
SRC = MapSRC.scanline(SizeY);
LAST = SRC + MapSRC.width();
while (SRC < LAST) *(DST++) = *(SRC++);
u32 SizeX;
nv::Color32 *DSTO2;
SizeX = MapSRC.width();
while ((SizeX>>1) >= MapDST.width())
{
DST = DSTO2 = LineMerg1;
LAST = DST + SizeX;
while (DST < LAST)
{
*(DSTO2++) = nv::Color32(((((u32)*(DST)) & 0xfefefefe)>>1) + ((((u32)*(DST+1)) & 0xfefefefe)>>1));
DST += 2;
}
SizeX >>= 1;
}
if (SizeX != MapDST.width())
{
u32 IncX,BasX;
BasX = 0;
IncX = ( MapDST.width()<<16) / SizeX;
DST = DSTO2 = LineMerg1;
LAST = DST + SizeX;
while (DST < LAST)
{
DSTO2[BasX>>16] = *(DST++);
BasX += IncX;
}
SizeX = MapDST.width();
}
PosY = (SizeY * MapDST.height()) / MapSRC.height();
if (PosY != LastPosY)
memcpy(MapDST.scanline(PosY),LineMerg1,SizeX * 4);
else
{
DSTO2 = LineMerg1;
DST = MapDST.scanline(PosY) ;
LAST = DST + SizeX;
while (DST < LAST)
{
*(DST++) = nv::Color32(((((u32)*(DST)) & 0xfefefefe)>>1) + ((((u32)*(DSTO2)) & 0xfefefefe)>>1));
DSTO2++;
}
}
LastPosY = PosY;
}
return btrue;
}
bbool ReduceLimitedScale(nv::Image & MapSRC,nv::Image & MapDST)
{
if (MapSRC.width() < MapDST.width() || MapSRC.width() > MapDST.width()*2)
return bfalse;
// MapSRC.width() < MapDST.width()*2
double ratioX = (f32)MapSRC.width() / (f32)MapDST.width();
double ratioY = (f32)MapSRC.height() / (f32)MapDST.height();
for (u32 SizeY = 0; SizeY < MapDST.height() ;SizeY++)
{
for (u32 SizeX = 0; SizeX < MapDST.width() ;SizeX++)
{
f32 xFloat = (f32)(SizeX * ratioX);
f32 yFloat = (f32)(SizeY * ratioY);
i32 x1 = (i32)xFloat;
i32 x2 = x1 + 1;
i32 y1 = (i32)yFloat;
i32 y2 = y1 + 1;
xFloat -= (f32)x1;
yFloat -= (f32)y1;
if (x1 >= (i32)MapSRC.width() || y1 >= (i32)MapSRC.height())
continue;
if (x2 >= (i32)MapSRC.width())
{
x2 = x1;
xFloat = 0.f;
}
if (y2 >= (i32)MapSRC.height())
{
y2 = y1;
yFloat = 0.f;
}
f32 xFloatInv = 1.f - xFloat;
f32 yFloatInv = 1.f - yFloat;
nv::Color32 c1 = MapSRC.pixel(x1, y1);
nv::Color32 c2 = MapSRC.pixel(x1, y2);
nv::Color32 c3 = MapSRC.pixel(x2, y1);
nv::Color32 c4 = MapSRC.pixel(x2, y2);
MapDST.pixel(SizeX, SizeY) = nv::Color32(
u8( c1.r*xFloatInv*yFloatInv + c2.r*xFloatInv*yFloat + c3.r*xFloat*yFloatInv + c4.r*xFloat*yFloat ),
u8( c1.g*xFloatInv*yFloatInv + c2.g*xFloatInv*yFloat + c3.g*xFloat*yFloatInv + c4.g*xFloat*yFloat ),
u8( c1.b*xFloatInv*yFloatInv + c2.b*xFloatInv*yFloat + c3.b*xFloat*yFloatInv + c4.b*xFloat*yFloat ),
u8( c1.a*xFloatInv*yFloatInv + c2.a*xFloatInv*yFloat + c3.a*xFloat*yFloatInv + c4.a*xFloat*yFloat ));
}
}
return btrue;
}
void ReduceDiv2(nv::Image & MapSRC,nv::Image & MapDST)
{
nv::Color32 *LAST,*DST,*SRC,*SRC2;
for (u32 SizeY = 0; SizeY < MapDST.height() ;SizeY++)
{
DST = MapDST.scanline(SizeY);
LAST = DST + MapDST.width();
SRC = MapSRC.scanline(2*SizeY);
SRC2 = MapSRC.scanline(2*SizeY+1);
while (DST < LAST)
{
u32 A,B;
A = (((u32)*(SRC) & 0xfefefefe)>>1) + (((u32)*(SRC + 1) & 0xfefefefe)>>1);
B = (((u32)*(SRC2) & 0xfefefefe)>>1) + (((u32)*(SRC2 + 1) & 0xfefefefe)>>1);
*(DST++) = nv::Color32(((A & 0xfefefefe)>>1) + ((B & 0xfefefefe)>>1));
SRC += 2;
SRC2 += 2;
}
}
}
bbool ReduceResO2(nv::Image & MapSRC,nv::Image & MapDST, nv::Image::Format _dstFormat)
{
u32 baseX = 8;
u32 baseY = 8;
while (baseX * 2 <= MapSRC.width())
baseX *= 2;
while (baseY * 2 <= MapSRC.height())
baseY *= 2;
nv::Image* img[2];
u32 curImg = 0;
img[curImg] = new nv::Image();
img[curImg]->setFormat(_dstFormat);
img[curImg]->allocate(baseX, baseY);
//Reduce(MapSRC, *img[curImg]);
ReduceLimitedScale(MapSRC, *img[curImg]);
while (img[curImg]->width() != MapDST.width())
{
baseX /= 2;
baseY /= 2;
img[1-curImg] = new nv::Image();
img[1-curImg]->setFormat(_dstFormat);
img[1-curImg]->allocate(baseX, baseY);
ReduceDiv2(*img[curImg], *img[1-curImg]);
delete img[curImg];
curImg = 1-curImg;
}
MapDST = *img[curImg];
delete img[curImg];
return btrue;
}
///////////////////////////////////////////////////////////////////////////////////////////
bbool PbkMerger::buildPackedMap(const AnimPackerConfiguration &_config)
{
SafeArray<Patch*> sortedPatchList;
//SafeArray<BoxI> sortedMapSizes;
int minMapWidth=0, minMapHeight=0;
int totalArea=0;
computeFinalMapStartupSize(minMapWidth, minMapHeight, totalArea);
buildSortedPatches(sortedPatchList);
if (sortedPatchList.size() == 0)
return bfalse;
u32 finalWidth, finalHeight;
f32 packTextureRatio = 1.f;
if (_config.m_sampling)
PatchList::CURRENT_SAMPLING = _config.m_sampling;
if (_config.m_hdDownscaleMask & 1)
PatchList::CURRENT_SAMPLING = (u32) ((f32)PatchList::CURRENT_SAMPLING / _config.m_hdDownscale + 0.5f);
const char * fromHdStr = _config.m_hdDownscaleMask & 1 ? " from HD" : "";
String8 logStr;
f64 rs;
f32 timetocompte;
ListPatch initPatchs;
fillPackFromPatches(initPatchs, sortedPatchList);
u32 baseRatioWidth = getUpperPowerOf2(minMapWidth/PatchList::CURRENT_SAMPLING);
u32 baseRatioHeight = getUpperPowerOf2(minMapHeight/PatchList::CURRENT_SAMPLING);
PackingTexture packTexture(initPatchs, baseRatioWidth, baseRatioHeight, (f32)PatchList::CURRENT_SAMPLING);
rs = SYSTEM_ADAPTER->getTime();
packTexture.computeGrid();
timetocompte = (f32)(SYSTEM_ADAPTER->getTime()-rs);
logStr.setTextFormat("First grid process time :%0.02f s", timetocompte);
TexturePacker::PackerLog::s_main->addText(logStr.cStr());
finalWidth = packTexture.getWidth();
finalHeight = packTexture.getHeight();
// ratioMult == 2 or ratioMult == 1 because we always mult width before height
u32 ratioWH = finalWidth / finalHeight;
u32 ratioHW = finalHeight / finalWidth;
PackingTexture texturePackFinal;
bbool texturePackOk = bfalse;
u32 fillPercent = packTexture.m_minNeededGridElemts * 100 / (packTexture.getWidth()* packTexture.getHeight());
u32 fillPercentFinal= 0;
u32 tryIdx = 1;
#ifdef SIMULATE_HD
f32 beginRatioInit = (f32)packTexture.m_minNeededGridElemts / ((f32)packTexture.m_height*packTexture.m_width);
#else
if (!(_config.m_hdDownscaleMask & 1))
{
rs = SYSTEM_ADAPTER->getTime();
bbool computeOK = packTexture.packingPatch();
timetocompte = (f32)(SYSTEM_ADAPTER->getTime()-rs);
if (computeOK)
{
texturePackFinal = packTexture;
texturePackOk = btrue;
packTextureRatio = 1.f;
fillPercentFinal = fillPercent;
logStr.setTextFormat("grid %dx%d <Try %i - downscale: %.f%% > <<<SUCCEED>>> time :%0.02f s - fill percent: %d%%", PatchList::CURRENT_SAMPLING, PatchList::CURRENT_SAMPLING, 0, 0.f, timetocompte, fillPercent);
} else
{
logStr.setTextFormat("grid %dx%d <Try %i - downscale: %.f%% > <<<FAIL>>> time :%0.02f s - fill percent: %d%%", PatchList::CURRENT_SAMPLING, PatchList::CURRENT_SAMPLING, 0, 0.f, timetocompte, fillPercent);
}
TexturePacker::PackerLog::s_main->addText(logStr.cStr());
}
f32 beginRatioInit = (_config.m_hdDownscaleMask & 1) ? (f32)packTexture.m_minNeededGridElemts / ((f32)packTexture.m_height*packTexture.m_width) : 1.f;
#endif
if (beginRatioInit < 0.5f)
beginRatioInit = 0.5f;
f32 endRatioInit = 1.15f;
while (!texturePackOk)
{
f32 beginRatio = beginRatioInit;
f32 endRatio = endRatioInit;
while (endRatio - beginRatio > 0.01f )
{
f32 ratio = (endRatio + beginRatio)*0.5f;
f32 trueRatio;
rs = SYSTEM_ADAPTER->getTime();
if (ratioWH)
{
u32 newHeight = (u32)(finalHeight * ratio + 0.5f);
packTexture.reset(initPatchs, newHeight*ratioWH, newHeight, (f32)PatchList::CURRENT_SAMPLING);
trueRatio = (f32)newHeight / (f32)finalHeight;
} else
{
u32 newWidth = (u32)(finalWidth * ratio + 0.5f);
packTexture.reset(initPatchs, newWidth, newWidth*ratioHW, (f32)PatchList::CURRENT_SAMPLING);
trueRatio = (f32)newWidth / (f32)finalWidth;
}
packTexture.computeGrid();
fillPercent = packTexture.m_minNeededGridElemts * 100 / (packTexture.getWidth()* packTexture.getHeight());
bbool computeOK = bfalse;
if (fillPercentFinal <= fillPercent)
computeOK = packTexture.packingPatch();
timetocompte = (f32)(SYSTEM_ADAPTER->getTime()-rs);
if (computeOK)
{
packTextureRatio = trueRatio;
logStr.setTextFormat("grid %dx%d <Try %i - downscale: %.f%% > <<<SUCCEED>>> time :%0.02f s - fill percent: %d%%", PatchList::CURRENT_SAMPLING, PatchList::CURRENT_SAMPLING,tryIdx, (packTextureRatio-1)*100, timetocompte, fillPercent);
texturePackFinal = packTexture;
texturePackOk = btrue;
endRatio = ratio;
fillPercentFinal = fillPercent;
} else
{
logStr.setTextFormat("grid %dx%d <Try %i - downscale: %.f%% > <<<FAIL>>> time :%0.02f s - fill percent: %d%%", PatchList::CURRENT_SAMPLING, PatchList::CURRENT_SAMPLING,tryIdx, (ratio-1)*100, timetocompte, fillPercent);
beginRatio = ratio;
}
TexturePacker::PackerLog::s_main->addText(logStr.cStr());
tryIdx++;
}
if (!texturePackOk)
{
if (finalWidth <= finalHeight)
finalWidth *= 2;
else
finalHeight *= 2;
ratioWH = finalWidth / finalHeight;
ratioHW = finalHeight / finalWidth;
}
}
packTexture = texturePackFinal;
TexturePacker::PackerLog::s_main->addText("------>> Start image generation");
rs = SYSTEM_ADAPTER->getTime();
ListPatch patchs = packTexture.getPatchsList();
packTexture.recomputeRotation(patchs);
TexturePacker::PackerLog::s_main->resetProgressbar(initPatchs.size());
for (u32 patchIndex=0; patchIndex<initPatchs.size(); patchIndex++)
{
PackingPatch & packingPatch = patchs[patchIndex];
for (u32 srcIdx=0; srcIdx<packingPatch.m_srcData.size(); srcIdx++)
{
Patch *patch = sortedPatchList[packingPatch.m_srcData[srcIdx]];
if (patch->getSourceOfAlias())
continue;
BoxI result;
Transform2d uvTransform;
result = BoxI((int)packingPatch.m_translation.x(),
(int)packingPatch.m_translation.y(),
(int)packingPatch.m_translation.x()+(int)(packingPatch.m_obb.getWidth() + 0.5f),
(int)packingPatch.m_translation.y()+(int)(packingPatch.m_obb.getHeight() + 0.5f));
matrix2d rot;
f32 rotation = -packingPatch.m_rotation;
rot.set( f32_Cos(rotation), -f32_Sin(rotation),
f32_Sin(rotation), f32_Cos(rotation));
Vec2d dstPos;
Vec2d _globalDelta = packingPatch.m_points[packingPatch.m_subPoly[srcIdx].m_begin] - mulMatrix2d(rot, patch->getPointList()[0]);
dstPos = _globalDelta + mulMatrix2d(rot, Vec2d((f32)patch->getUVBox().minx, (f32)patch->getUVBox().miny) - patch->getProcessDelta());
rotation = -packingPatch.m_rotation;
uvTransform.m_rot.set( f32_Cos(rotation), -f32_Sin(rotation),
f32_Sin(rotation), f32_Cos(rotation));
uvTransform.m_pos = dstPos - packingPatch.m_translation;
patch->setAngle(rotation);
patch->setFinalPos(result, uvTransform);
patch->setSample(packingPatch.m_widthSampling, packingPatch.m_heightSampling, packingPatch.m_sampling);
}
TexturePacker::PackerLog::s_main->progressbarStep();
}
for (u32 patchIndex=0; patchIndex<sortedPatchList.size(); patchIndex++)
{
Patch *patch = sortedPatchList[patchIndex];
if (!patch->getSourceOfAlias())
continue;
patch->setFinalPosFromAlias();
}
m_grid = packTexture.m_grid;
m_gridWidth = packTexture.m_width;
m_gridHeight= packTexture.m_height;
bbool isOk=btrue;
bbool isFirst = btrue;
for (u32 textIdx=0; textIdx<(u32)TEXSET_ID_COUNT; textIdx++)
{
if (!(m_imgMask & (1<<textIdx) ))
continue;
nv::Image::Format dstFormat = nv::Image::Format_RGB;
if (m_imgUseAlphaMask & (1<<textIdx))
dstFormat = nv::Image::Format_ARGB;
SafeArray<BoxI> aabbList;
ITF_VECTOR<nv::Image> imgList;
u32 mapWidth = packTexture.getWidth()*PatchList::CURRENT_SAMPLING;
u32 mapHeight = packTexture.getHeight()*PatchList::CURRENT_SAMPLING;
u32 nbXPart = 1;
u32 nbYPart = 1;
u32 marge = 2;
if (mapWidth * mapHeight > 0x5100000)
{
u32 midWidth = mapWidth / 2;
u32 midHeight = mapHeight / 2;
aabbList.push_back(BoxI(0 , 0 , midWidth, midHeight));
aabbList.push_back(BoxI(midWidth, 0 , mapWidth, midHeight));
aabbList.push_back(BoxI(0 , midHeight , midWidth, mapHeight));
aabbList.push_back(BoxI(midWidth, midHeight , mapWidth, mapHeight));
nbXPart = 2;
nbYPart = 2;
} else
{
aabbList.push_back(BoxI(0, 0, mapWidth, mapHeight));
}
for (u32 aabbIter = 0; aabbIter < aabbList.size(); aabbIter++)
{
const BoxI & curBox = aabbList[aabbIter];
nv::Image partImage;
partImage.setFormat(dstFormat);
partImage.allocate(curBox.maxx-curBox.minx, curBox.maxy-curBox.miny);
partImage.fill(nv::Color32(0,0,0,0));
blitFinalImage(partImage, curBox.minx, curBox.miny, sortedPatchList, (TextureSetSubID)textIdx);
f32 finalRatio = ((m_hdDownscaleMask & (1<<textIdx)) ? _config.m_hdDownscale : 1.f) / packTextureRatio;
if (!isFirst)
finalRatio *= 0.5;
ITF_ASSERT(finalRatio <= 1.f);
if (finalRatio < 1.f)
{
nv::Image subImage;
subImage.setFormat(dstFormat);
u32 width = (u32)((f32)mapWidth * finalRatio) - 1; // -1 will not change pow 2 !
u32 height = (u32)((f32)mapHeight * finalRatio) - 1; // -1 will not change pow 2 !
width = getUpperPowerOf2(width) / nbXPart;
height = getUpperPowerOf2(height) / nbYPart;
subImage.allocate(width, height);
ReduceResO2(partImage, subImage, dstFormat);
partImage = subImage;
}
imgList.push_back(partImage);
}
isFirst = bfalse;
nv::Image finalImage;
if (imgList.size() == 1)
finalImage = imgList[0];
else
{
u32 finalW = 0;
u32 finalH = 0;
for (u32 x=0; x<nbXPart; x++)
finalW += imgList[x].width();
for (u32 y=0; y<nbYPart; y++)
finalH += imgList[y*nbXPart].height();
finalImage.setFormat(dstFormat);
finalImage.allocate(finalW, finalH);
i32 curPixelY = 0;
for (u32 y=0; y<nbYPart; y++)
{
i32 curPixelX = 0;
for (u32 x=0; x<nbXPart; x++)
{
nv::Image & img = imgList[x + y*nbXPart];
u32 lineSize = img.width()*4;
for (u32 yPx = 0; yPx < img.height(); yPx++)
{
nv::Color32 * srcLine = img.scanline(yPx);
nv::Color32 * dstLine = finalImage.scanline(yPx + curPixelY) + curPixelX;
ITF_Memcpy(dstLine, srcLine, lineSize);
}
curPixelX += img.width();
}
curPixelY += imgList[y*nbXPart].height();
}
}
blitFinalImageData(mapWidth, mapHeight, sortedPatchList);
bbool saved = bfalse;
String8 name;
name.setTextFormat("%s_%i.tga", getCompositeName().cStr(), textIdx);
Path imagePath = _config.m_mainPath.copyAndChangeBasename(name);
if (SOURCECONTROL_ADAPTER)
SOURCECONTROL_ADAPTER->checkout(imagePath);
String8 translated = FILESERVER->platformString8FromPath(imagePath);
saved = nv::ImageIO::save(translated.cStr(), &finalImage);
// we are not sure that the file is in perforce, so we add it
if (SOURCECONTROL_ADAPTER)
SOURCECONTROL_ADAPTER->add(imagePath);
if (!saved)
{
ITF_ERROR("Could not write %s", imagePath.toString8().cStr());
}
isOk=saved;
}
timetocompte = (f32)(SYSTEM_ADAPTER->getTime()-rs);
logStr.setTextFormat("Time to generate images%s: %0.02f s", fromHdStr, timetocompte);
TexturePacker::PackerLog::s_main->addText(logStr.cStr());
return isOk;
}
}
}