#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 (a1getSubImageWidth()+patch1->getSubImageHeight(); int halfPerim2 = patch2->getSubImageWidth()+patch2->getSubImageHeight(); if (halfPerim1 &_sortedPatchList) { _sortedPatchList.reserve(500); ITF_LIST::iterator patchListIter; for (patchListIter=m_listOfPatchLists.begin(); patchListIter!=m_listOfPatchLists.end(); patchListIter++) { PatchList *patchList = *patchListIter; ITF_LIST::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::iterator patchListIter; for (patchListIter=m_listOfPatchLists.begin(); patchListIter!=m_listOfPatchLists.end(); patchListIter++) { PatchList *patchList = *patchListIter; ITF_LIST::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::iterator patchListIter; for (patchListIter=m_listOfPatchLists.begin(); patchListIter!=m_listOfPatchLists.end(); patchListIter++) { PatchList *patchList = *patchListIter; ITF_LIST::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::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; nameIndexm_NameToTemplate.size(); nameIndex++) { u32 key = patchBank->m_NameToTemplate.getKeyAt(nameIndex); if (_patchDepot) { bbool isUsed = bfalse; for (ITF_LIST::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 &_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 &_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 &_inputPatchList) { ITF_SET 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 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; xym_sampling[xy] ? 1 : 0; return packPatch; } #define LIMIT_ONE 2 #define LIMIT_TWO 130 / 100 void fillPackFromPatches(ListPatch & _initPatchs, const SafeArray _sortedPatchList) { // First check for common AABB patches BoxI resultBox; KeyArray> processedMap; SafeArray 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 &childs = processedMap.getAt(idx); childs.push_back(j); } else { SafeArray 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 & childs = processedMap.getAt(i); PackingPatch paaa; for (u32 j=0; j & 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; kgetSourceOfAlias()) 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 sortedPatchList; //SafeArray 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 <<>> time :%0.02f s - fill percent: %d%%", PatchList::CURRENT_SAMPLING, PatchList::CURRENT_SAMPLING, 0, 0.f, timetocompte, fillPercent); } else { logStr.setTextFormat("grid %dx%d <<>> 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 <<>> 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 <<>> 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; patchIndexgetSourceOfAlias()) 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; patchIndexgetSourceOfAlias()) 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< aabbList; ITF_VECTOR 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<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; } } }