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

901 lines
36 KiB
C++

#include "stdafx.h"
#ifndef _ITF_ANIMTEXPACKER_PATCH_H_
#include "AnimTexPacker/Patch.h"
#endif
#ifndef _ITF_GFX_ADAPTER_H_
#include "engine/AdaptersInterfaces/GFXAdapter.h"
#endif //_ITF_GFX_ADAPTER_H_
#ifndef _ITF_ANIMATIONSKELETON_H_
#include "engine/animation/AnimationSkeleton.h"
#endif // _ITF_ANIMATIONSKELETON_H_
#ifndef _ITF_ANIMATIONPATCHBANK_H_
#include "engine/animation/AnimationPatchBank.h"
#endif // _ITF_ANIMATIONPATCHBANK_H_
#ifndef _ITF_ANIMATIONDRAW_H_
#include "engine/animation/AnimationDraw.h"
#endif // _ITF_ANIMATIONDRAW_H_
#ifndef _ITF_STATSMANAGER_H_
#include "engine/stats/statsManager.h"
#endif //_ITF_STATSMANAGER_H_
namespace ITF
{
namespace AnimTexPacker
{
u32 PatchList::CURRENT_SAMPLING = 16;
///////////////////////////////////////////////////////////////////////////////////////////
class SimplePatch32Data
{
public:
static const int maxVertexCount=MAX_VERTEX_BY_MESH;
SimplePatch32Data() {vertexCount=0;indexCount=0;}
VertexPT vertexListPT[maxVertexCount];
u32 vertexCount;
u32 indexCount;
};
Path Patch::m_saveInFile;
u32 Patch::s_patchHdiv = PATH_HDIV_DEF;
Patch::~Patch()
{
for (u32 i=0; i<m_pixelsTab.size(); i++)
{
SF_DEL_ARRAY(m_pixelsTab[i]);
if (!m_saveInFile.isEmpty())
{
Path savePath = getPixelsTabFileName(i);
if (hwFile::exists(savePath))
hwFile::deleteFile(savePath);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::setFinalPos(const BoxI &_finalBox, const Transform2d &_uvTransform)
{
m_finalPos = _finalBox;
m_uvlocalToRotatedLocalTransform = _uvTransform;
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::setFinalPosFromAlias()
{
ITF_ASSERT(getSourceOfAlias());
m_finalPos = m_sourceOfAlias->m_finalPos;
m_uvlocalToRotatedLocalTransform = m_sourceOfAlias->m_uvlocalToRotatedLocalTransform;
}
///////////////////////////////////////////////////////////////////////////////////////////
int Patch::computePlacementHeuristic(PackedTextureArea *_area, BoxI &b)
{
int x,y;
int count=0;
//upper edge
y=b.miny-1;
for (x = b.minx - 1; x <= b.maxx + 1; x++)
if (_area->testBorder(x, y))
count++;
//lower edge
y=b.maxy+1;
for (x = b.minx - 1; x <= b.maxx + 1; x++)
if (_area->testBorder(x, y))
count++;
//left edge
x = b.minx - 1;
for (y = b.miny; y <= b.maxy; y++)
if (_area->testBorder(x, y))
count++;
//right edge
x = b.maxx + 1;
for (y = b.miny; y <= b.maxy; y++)
if (_area->testBorder(x, y))
count++;
return count;
}
///////////////////////////////////////////////////////////////////////////////////////////
bbool Patch::Place(PackedTextureArea *_area, BoxI &b, bbool &_rotated, Transform2d &_subImageRotation)
{
b = BoxI(0, 0, m_UVBox.maxx-m_UVBox.minx, m_UVBox.maxy-m_UVBox.miny);
int bestHeuristic = -1;
int bestx=0, besty=0;
int bestPhase = 0;
int w = getSubImageWidth();
int h = getSubImageHeight();
ITF_SET<int> placeableX, placeableY;
ITF_SET<int>::const_iterator xiter, yiter;
ITF_ASSERT(!getSourceOfAlias());
//regular orientation
_area->computeRemarkablePlacesForBox(placeableX, placeableY, w,h);
for (yiter=placeableY.begin(); yiter!=placeableY.end(); yiter++)
for (xiter = placeableX.begin(); xiter!=placeableX.end();xiter++)
{
int x = *xiter;
int y = *yiter;
b.minx = x;
b.miny = y;
b.maxx = x + w - 1;
b.maxy = y + h - 1;
int heur = computePlacementHeuristic(_area, b);
if (heur > bestHeuristic)
{
if (_area->isAreaFree(x, y, w, h))
{
bestHeuristic = heur;
bestx = x;
besty = y;
bestPhase = 0;
}
}
}
#if 0
//rotated orientation
_area->computeRemarkablePlacesForBox(placeableX, placeableY, h,w);
for (yiter=placeableY.begin(); yiter!=placeableY.end(); yiter++)
for (xiter = placeableX.begin(); xiter!=placeableX.end();xiter++)
{
int x = *xiter;
int y = *yiter;
b.minx = x;
b.miny = y;
b.maxx = x + h - 1;
b.maxy = y + w - 1;
int heur = computePlacementHeuristic(_area, b);
if (heur > bestHeuristic)
{
if (_area->isAreaFree(x, y, h, w))
{
bestHeuristic = heur;
bestx = x;
besty = y;
bestPhase = 1;
}
}
}
#endif
//
if (bestPhase == 0)
{
b.minx = bestx;
b.miny = besty;
b.maxx = bestx + w - 1;
b.maxy = besty + h - 1;
_rotated = bfalse;
_subImageRotation.setIdentity();
}
else if (bestPhase == 1)
{
b.minx = bestx;
b.miny = besty;
b.maxx = bestx + h - 1;
b.maxy = besty + w - 1;
_rotated = btrue;
Vec2d nextZero(0,(f32)m_subImageHeight-1);
_subImageRotation.m_rot.set(0.f,1.f,-1.f,0.f);
_subImageRotation.m_pos = -mulMatrix2d(_subImageRotation.m_rot, nextZero);
}
else
{
ITF_ASSERT(bfalse);
}
if (bestHeuristic < 0)
return bfalse;
_area->fillBox(b);
return btrue;
}
///////////////////////////////////////////////////////////////////////////////////////////
bbool Patch::isEqual(const Patch *_other)
{
if (m_diffuseImagePath!=_other->m_diffuseImagePath)
return bfalse;
if (m_UVBox != _other->m_UVBox)
return bfalse;
return btrue;
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::initialize(const StringID &_bankID, const StringID &_templateID, AnimTemplate *_animTemplate, ChainedBones &_chainedBones, ITF_VECTOR<ImageTextureMode> &_imageTab, const Path& _diffuseImagePath, AnimSkeleton *_skeleton)
{
m_bankID = _bankID;
m_diffuseImagePath = _diffuseImagePath;
m_templateID = _templateID;
m_boneIndices.resize(0);
nv::Image & firstImage = _imageTab[0].m_image;
m_initialImageWidth = (int)firstImage.width();
m_initialImageHeight = (int)firstImage.height();
m_animTemplate = _animTemplate;
m_skeleton = _skeleton;
computeUVAABB(_animTemplate, _chainedBones, firstImage);
u32 animBoneCount=_chainedBones.m_AnimBones.size();
m_boneIDs.resize(0);
m_boneIDs.reserve(animBoneCount);
m_boneIndices.reserve(animBoneCount);
for (u32 i=0; i<animBoneCount; i++)
{
AnimBone *bone = _chainedBones.m_AnimBones[i];
u32 boneIndex = (u32)_skeleton->getBoneIndex(bone->m_Name);
m_boneIndices.push_back(boneIndex);
m_boneIDs.push_back(bone->m_Name);
}
for (u32 i=0; i<_imageTab.size(); i++)
extractPixels(_imageTab[i].m_image, _imageTab[i].m_mode);
}
Path Patch::getPixelsTabFileName(u32 _idx)
{
Path filename(m_saveInFile);
String8 name;
name.setTextFormat(m_saveInFile.getBasename(), m_serialNumber, _idx);
filename.changeBasename(name);
return filename;
}
nv::Color32 * Patch::savePixelsTab(nv::Color32 * _pixelTab, u32 _idx)
{
if (m_saveInFile.isEmpty())
return _pixelTab;
hwFile* file = newAlloc(mId_Temporary, hwFile());
if ( !file->open( getPixelsTabFileName(_idx), ITF_FILE_ATTR_CREATE_NEW | ITF_FILE_ATTR_WRITE ) )
{
SF_DEL( file );
return _pixelTab;
}
file->write( _pixelTab, m_subImageHeight*m_subImageWidth*sizeof(nv::Color32));
file->close();
SF_DEL_ARRAY(_pixelTab);
SF_DEL( file );
return NULL;
}
nv::Color32 * Patch::loadPixelsTab(nv::Color32 * _pixelTab, u32 _idx)
{
if (_pixelTab)
return _pixelTab;
if (m_saveInFile.isEmpty())
return _pixelTab;
hwFile* file = newAlloc(mId_Temporary, hwFile());
if ( !file->open( getPixelsTabFileName(_idx), ITF_FILE_ATTR_READ ) )
{
SF_DEL( file );
return _pixelTab;
}
_pixelTab = newAlloc(mId_Temporary,nv::Color32[m_subImageHeight*m_subImageWidth]);
file->read( _pixelTab, m_subImageHeight*m_subImageWidth*sizeof(nv::Color32));
file->close();
SF_DEL( file );
return _pixelTab;
}
void Patch::extractPixels(nv::Image &_image, u32 _idx)
{
m_subImageWidth = getUVBoundingWidth();
m_subImageHeight = getUVBoundingHeight();
bbool useAlphaZero = (_image.format() == nv::Image::Format_RGB) && _idx > 0;
if (_idx >= m_pixelsTab.size())
{
u32 prevSize = m_pixelsTab.size();
m_pixelsTab.resize(_idx+1);
for (u32 i=prevSize; i<m_pixelsTab.size(); i++)
m_pixelsTab[i] = NULL;
}
m_pixelsTab[_idx] = newAlloc(mId_Temporary,nv::Color32[m_subImageHeight*m_subImageWidth]);
nv::Color32 emptyColor(0,0,0,0);
nv::Color32 *dest = m_pixelsTab[_idx];
for (int y=m_UVBox.miny; y<=m_UVBox.maxy; y++)
{
const nv::Color32 *c = _image.scanline(y);
bbool isYInFrame=(y>=0 && y<m_initialImageHeight);
for (int x=m_UVBox.minx; x<=m_UVBox.maxx; x++)
{
if (isYInFrame && x>=0 && x<m_initialImageWidth)
{
*dest = c[x];
if (useAlphaZero)
dest->a = 0;
dest++;
}
else
*dest++ = emptyColor;
}
}
ITF_ASSERT(dest==m_pixelsTab[_idx]+m_subImageWidth*m_subImageHeight);
m_pixelsTab[_idx] = savePixelsTab(m_pixelsTab[_idx], _idx);
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::blitToFinalPos(nv::Image &_destImage, i32 xOffset, i32 yOffset, u32 _idx)
{
ITF_ASSERT(!getSourceOfAlias());
if (!m_sampling.size())
return;
if (_idx >= m_pixelsTab.size())
return;
u32 finalW = m_widthSampling *PatchList::CURRENT_SAMPLING;
u32 finalH = m_heightSampling*PatchList::CURRENT_SAMPLING;
i32 destWidth = _destImage.width();
i32 destHeight = _destImage.height();
if ((m_finalPos.minx-xOffset) > destWidth ||
(m_finalPos.miny-yOffset) > destHeight ||
(m_finalPos.minx + finalW - xOffset) < 0 ||
(m_finalPos.maxy + finalH - yOffset) < 0)
return;
m_pixelsTab[_idx] = loadPixelsTab(m_pixelsTab[_idx], _idx);
if (!m_pixelsTab[_idx])
return;
nv::Color32 *dest = _destImage.pixels();
matrix2d invRotation;
invRotation.set(m_uvlocalToRotatedLocalTransform.m_rot.m_col1.x(),
m_uvlocalToRotatedLocalTransform.m_rot.m_col2.x(),
m_uvlocalToRotatedLocalTransform.m_rot.m_col1.y(),
m_uvlocalToRotatedLocalTransform.m_rot.m_col2.y());
Color dstColor;
for (u32 y=0; y<finalH; y++)
{
for (u32 x=0; x<finalW; x++)
{
if (!m_sampling[(x/PatchList::CURRENT_SAMPLING) + (y/PatchList::CURRENT_SAMPLING)*m_widthSampling])
continue;
Vec2d srcPos = Vec2d((f32)x-m_uvlocalToRotatedLocalTransform.m_pos.x(),
(f32)y-m_uvlocalToRotatedLocalTransform.m_pos.y());
Vec2d posUV = mulMatrix2d(invRotation, srcPos);
if (posUV.x() >= 0 && posUV.x() < m_subImageWidth &&
posUV.y() >= 0 && posUV.y() < m_subImageHeight)
{
int x0 = (int)posUV.x();
int x1 = x0 + 1;
int y0 = (int)posUV.y();
int y1 = y0 + 1;
Color c00(getPixel_WithBorder(x0,y0,_idx));
Color c10(getPixel_WithBorder(x1,y0,_idx));
Color c01(getPixel_WithBorder(x0,y1,_idx));
Color c11(getPixel_WithBorder(x1,y1,_idx));
int offsetX = x + m_finalPos.minx - xOffset;
int offsetY = y + m_finalPos.miny - yOffset;
int offset = offsetX + offsetY*destWidth;
if (offsetX >= 0 && offsetX < destWidth &&
offsetY >= 0 && offsetY < destHeight)
{
f32 xratio = posUV.x() - x0;
f32 yratio = posUV.y() - y0;
dstColor = c00*(1-xratio)*(1-yratio) +
c10*xratio*(1-yratio) +
c01*(1-xratio)*yratio +
c11*xratio*yratio;
nv::Color32 drawColor = nv::Color32(dstColor.getAsU32());
if (dest[offset].a < drawColor.a) dest[offset].a = drawColor.a;
if (dest[offset].r < drawColor.r) dest[offset].r = drawColor.r;
if (dest[offset].g < drawColor.g) dest[offset].g = drawColor.g;
if (dest[offset].b < drawColor.b) dest[offset].b = drawColor.b;
}
}
}
}
if (!m_saveInFile.isEmpty())
{
SF_DEL_ARRAY(m_pixelsTab[_idx]);
}
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::growPatchMaxSize(const BoneMaxSize& _toAdd )
{
m_boneMaxSize.grow(_toAdd.m_worldSize.getMax(), _toAdd.m_uvSize.getMax());
}
const BoneMaxSize &Patch::getPatchMaxSize() const
{
ITF_ASSERT(!getSourceOfAlias());
return m_boneMaxSize;
}
///////////////////////////////////////////////////////////////////////////////////////////
//void Patch::resizeTexture(int _newSize)
//{
// ITF_ASSERT(!getSourceOfAlias());
// int w = getSubImageWidth();
// int h = getSubImageHeight();
// if (w>=h)
// {
// float ratio = h/(float)w;
// w = _newSize;
// h = (int) (_newSize*ratio);
// if (h<1)
// h = 1;
// }
// else
// {
// float ratio = w/(float)h;
// h = _newSize;
// w = (int) (_newSize*ratio);
// if (w<1)
// w = 1;
// }
// int srcWidth = getSubImageWidth();
// int srcHeight = getSubImageHeight();
// m_imageStretchTransform.m_rot.set(w/(f32)srcWidth, 0,0, h/(f32)srcHeight);
// m_imageStretchTransform.m_pos.set(0,0);
// ITF_ASSERT(w<srcWidth && h<srcHeight);
// u32 imgCount = m_pixelsTab.size();
// for (u32 imgIdx=0; imgIdx<imgCount; imgIdx++)
// {
// nv::Color32 *newPixels = new nv::Color32[w*h];
// for (int y=0; y<h; y++)
// {
// for (int x=0; x<w; x++)
// {
// f32 xInSource_Start = x*(srcWidth/(f32)w);
// f32 xInSource_End = (x+1)*(srcWidth/(f32)w);
// xInSource_End = Min(xInSource_End, (f32)srcWidth);
// f32 yInSource_Start = y*(srcHeight/(f32)h);
// f32 yInSource_End = (y+1)*(srcHeight/(f32)h);
// yInSource_End = Min(yInSource_End, (f32)srcHeight);
// int pixelCount = 0;
// int pixelR=0, pixelG=0, pixelB=0, pixelA=0;
// for (float subY=yInSource_Start; subY<yInSource_End; subY = floorf(subY)+1.f)
// {
// for (float subX=xInSource_Start; subX<xInSource_End; subX = floorf(subX)+1.f)
// {
// nv::Color32 c = samplePixel_Linear(subX, subY, imgIdx);
// pixelR += c.r;
// pixelG += c.g;
// pixelB += c.b;
// pixelA += c.a;
// pixelCount++;
// }
// }
// nv::Color32 mean(0,0,0,0);
// ITF_ASSERT(pixelCount!=0);
// if (pixelCount!=0)
// {
// mean.r = (u8)(pixelR/pixelCount);
// mean.g = (u8)(pixelG/pixelCount);
// mean.b = (u8)(pixelB/pixelCount);
// mean.a = (u8)(pixelA/pixelCount);
// }
// newPixels[x+y*w] = mean;
// }
// }
// //
// delete [] m_pixelsTab[imgIdx];
// m_pixelsTab[imgIdx] = newPixels;
// }
// m_subImageWidth = w;
// m_subImageHeight = h;
//}
///////////////////////////////////////////////////////////////////////////////////////////
nv::Color32 Patch::samplePixel_Linear(f32 _x, f32 _y, u32 _idx)
{
f32 xInSource = _x;
f32 yInSource = _y;
double dummyDouble;
int x0 = (int)xInSource;
int srcWidth = (int)getSubImageWidth();
int srcHeight = (int)getSubImageHeight();
int x1 = Min(srcWidth-1, x0+1);
int y0 = (int)yInSource;
int y1 = Min(srcHeight-1, y0+1);
f32 fracX = (float)modf(xInSource, &dummyDouble);
f32 fracY = (float)modf(yInSource, &dummyDouble);
f32 invFracX = 1-fracX;
f32 invFracY = 1-fracY;
nv::Color32 p00 = getPixel(x0,y0,_idx);
nv::Color32 p10 = getPixel(x1,y0,_idx);
nv::Color32 p01 = getPixel(x0,y1,_idx);
nv::Color32 p11 = getPixel(x1,y1,_idx);
float w00 = invFracX*invFracY;
float w10 = fracX*invFracY;
float w01 = invFracX*fracY;
float w11 = fracX*fracY;
int r = (int)(p00.r*w00 + p10.r*w10 + p01.r*w01 + p11.r*w11);
int g = (int)(p00.g*w00 + p10.g*w10 + p01.g*w01 + p11.g*w11);
int b = (int)(p00.b*w00 + p10.b*w10 + p01.b*w01 + p11.b*w11);
int a = (int)(p00.a*w00 + p10.a*w10 + p01.a*w01 + p11.a*w11);
return nv::Color32((u8)r,(u8)g,(u8)b,(u8)a);
}
///////////////////////////////////////////////////////////////////////////////////////////
void Patch::modifyUVs(int mapWidth, int mapHeight, ITF_SET<AnimPatchPoint*> &_alreadyProcessedPoints)
{
if (m_uvModified)
return;
m_uvModified = btrue;
//Compute, for UV space : OriginalUV->truncatedInteger->rotatedInteger->placedInteger->final
Transform2d originalToTruncated, truncatedRotatedToStretched, truncatedToRotated, rotatedToPlaced, placedToFinal;
originalToTruncated.m_rot.set((f32)m_initialImageWidth, 0, 0, (f32)m_initialImageWidth);
originalToTruncated.m_pos = - Vec2d((f32)m_UVBox.minx, (f32)m_UVBox.miny);
Patch *transformSource = getSourceOfAlias();
if (!transformSource)
transformSource = this;
truncatedToRotated = transformSource->m_uvlocalToRotatedLocalTransform;
truncatedRotatedToStretched = transformSource->m_imageStretchTransform;
rotatedToPlaced.m_rot.setIdentity();
rotatedToPlaced.m_pos = Vec2d((f32)m_finalPos.minx+0.5f, (f32)m_finalPos.miny+0.5f);
placedToFinal.m_rot.set(1.f/mapWidth, 0, 0, 1.f/mapWidth);
placedToFinal.m_pos.set(0,0);
Transform2d uvFinalTransform = placedToFinal*rotatedToPlaced*truncatedRotatedToStretched*truncatedToRotated*originalToTruncated;
//we compute an uniform tranform, which doesnt take whole texture shapes, because rectangular textures can make UV squashed
Transform2d uvVectorTranformUniform = rotatedToPlaced*truncatedRotatedToStretched*truncatedToRotated;
//We modify Pos, PosEnd for each bone seed (hierarchy start). Seed is at index 0 for m_boneIndices
for (u32 boneIndexInList=0; boneIndexInList<m_boneIDs.size(); boneIndexInList++)
{
i32 boneIDIndex = m_animTemplate->m_NameToBone.find(m_boneIDs[boneIndexInList]);
i32 boneIndex = -1;
if (boneIDIndex>=0)
boneIndex = m_animTemplate->m_NameToBone.getAt(boneIDIndex);
ITF_ASSERT(boneIndex>=0 && boneIndex<(i32)m_animTemplate->m_BonesCurFrameDyn.size());
AnimBoneDyn *seedBone = &m_animTemplate->m_BonesCurFrameDyn[boneIndex];
ITF_ASSERT(seedBone);
//f32 localAngleRad = seedBone->m_AngleLocal;
//f32 localAngleRad = seedBone->m_Angle;
if (boneIndexInList==0)
{
seedBone->m_Pos = mulTransform2d(uvFinalTransform, seedBone->m_Pos);
seedBone->m_Angle += transformSource->m_angle;
}
//the following code may have problems with non-square textures or rotation. we should use X ratio instead
Vec2d boneLenVec(seedBone->m_Scale.x(), 0);
boneLenVec = mulMatrix2d(uvFinalTransform.m_rot, boneLenVec);
seedBone->m_Scale.x() = boneLenVec.norm();
}
//each AnimTemplate is broken in several Patch,
//so we need to iterate each AnimPatch in it to check it's connected to a bone related to the Patch
//If so, we can modify the points in the AnimPatch
for (u32 patchIndex=0; patchIndex<m_animTemplate->m_Patch.size(); patchIndex++)
{
AnimPatch *patch = &m_animTemplate->m_Patch[patchIndex];
if (patch->m_nbPatchPoints!=0)
{
AnimBone *boneToFind = patch->m_AnimPatchPoints[0]->m_mainRefs.m_BonePtr;
u32 boneIndex=0;
ITF_ASSERT(boneToFind);
StringID idToFind = boneToFind->m_Name;
//In the bone in current patch list?
bbool isFound = bfalse;
for (boneIndex=0; boneIndex<m_boneIDs.size(); boneIndex++)
{
if (idToFind==m_boneIDs[boneIndex])
{
isFound = btrue;
break;
}
}
//if we are in right AnimPatch
if (isFound)
{
//
//modify points
for (u32 pointIndex=0; pointIndex<patch->m_nbPatchPoints; pointIndex++)
{
AnimPatchPoint *p = patch->m_AnimPatchPoints[pointIndex];
if (find(_alreadyProcessedPoints.begin(), _alreadyProcessedPoints.end(), p)!=_alreadyProcessedPoints.end())
continue;
_alreadyProcessedPoints.insert(p);
p->m_PosUV = mulTransform2d(uvFinalTransform, p->m_PosUV);
p->m_NormaleUV = mulMatrix2d(uvVectorTranformUniform.m_rot, p->m_NormaleUV);
p->m_NormaleUV.normalize();
//the following code may have problems with non-square textures or rotation. we should use Y ratio instead
Vec2d boneLenVec(0, f32_Abs(p->m_mainRefs.m_Pos.y()));
boneLenVec = mulMatrix2d(uvFinalTransform.m_rot, boneLenVec);
p->m_mainRefs.m_Pos.y() = boneLenVec.norm()*getSign(p->m_mainRefs.m_Pos.y());
//p->m_mainRefs.m_Pos.y() *= initialToFinalHeight;
//p->m_mainRefs.m_Normale = mulMatrix2d(uvVectorTranformUniform.m_rot, p->m_mainRefs.m_Normale);
//p->m_mainRefs.m_Normale.normalize();
}
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////
bbool Patch::computePatchUVAABB(AnimPatch *_patch, AABB &UVs, nv::Image &_image, Vec2d *_ptList)
{
struct TexDesc
{
u32 m_sizeX, m_sizeY;
f32 getRatioXY() {return (f32) m_sizeX/(f32) m_sizeY;}
} textureDesc;
UVs = AABB(Vec2d(0,0));
bbool isBoxInit=bfalse;
TexDesc *texture = &textureDesc;
SimplePatch32Data data;
SimplePatch32Data *_pData = &data;
Vec2d PointsNS[16];
const AnimPatchPointDyn *ppDynTab[4];
const AnimPatchPoint *ppTab[4];
AnimPatchPointDyn dummyDyn[4];
const u32 _hdiv = s_patchHdiv;
const u32 _vdiv = 1;
const f32 _z = 0;
textureDesc.m_sizeX = _image.width();
textureDesc.m_sizeY = _image.height();
ITF_MemSet(dummyDyn, 0, sizeof(dummyDyn));
if (_patch->m_nbPatchPoints == 4)
{
ppTab[0] = _patch->m_AnimPatchPoints[1];
ppTab[1] = _patch->m_AnimPatchPoints[3];
ppTab[2] = _patch->m_AnimPatchPoints[0];
ppTab[3] = _patch->m_AnimPatchPoints[2];
} else
{
ITF_ASSERT(_patch->m_nbPatchPoints == 2);
ppTab[0] = _patch->m_AnimPatchPoints[0];
ppTab[1] = _patch->m_AnimPatchPoints[1];
ppTab[2] = _patch->m_AnimPatchPoints[1];
ppTab[3] = _patch->m_AnimPatchPoints[0];
}
ppDynTab[0] = &dummyDyn[ppTab[0]->m_Index];
ppDynTab[1] = &dummyDyn[ppTab[1]->m_Index];
ppDynTab[2] = &dummyDyn[ppTab[2]->m_Index];
ppDynTab[3] = &dummyDyn[ppTab[3]->m_Index];
AnimDraw::computePatchControlPoints(&PointsNS[0],ppDynTab, ppTab, _hdiv, _vdiv, bfalse);
#undef PATCH32_USE_PCT
#undef PATCH32_USE_COLOR
#define PATCH32_DO_NOT_RETURN
#define PATCH32_IGNORE_MESHELEMENTS
#include "engine/AdaptersInterfaces/GFXAdapter_DrawPatch.h"
VertexPT * vertices = _pData->vertexListPT;
for (u32 vertIndex=0; vertIndex<_pData->vertexCount; vertIndex++)
{
_ptList[vertIndex] = vertices[vertIndex].m_uv;
if (!isBoxInit)
{
UVs = AABB(_ptList[vertIndex]);
isBoxInit = btrue;
}
else
{
UVs.grow(_ptList[vertIndex]);
}
}
ITF_ASSERT(_pData->vertexCount<SimplePatch32Data::maxVertexCount);
return isBoxInit;
}
struct SegmentPatch
{
i32 m_beginIndex;
i32 m_endIndex;
i32 m_nextIndex;
};
///////////////////////////////////////////////////////////////////////////////////////////
///compute uv aabb from animation data
void Patch::computeUVAABB(AnimTemplate *_template, ChainedBones &_chainedBones, nv::Image &_image)
{
AABB UVs(Vec2d(0,0));
bbool isUVInit=bfalse;
u32 lineSize = (s_patchHdiv+1);
u32 pathSize = lineSize*2;
SafeArray<Vec2d> pointListTmp1;
SafeArray<Vec2d> pointListTmp2;
for (int boneIndex=0; boneIndex<(int)_chainedBones.m_AnimBones.size(); boneIndex++)
{
AnimBone *bone = _chainedBones.m_AnimBones[boneIndex];
//for each patch linked to this bone
for (u32 patchIndex=0; patchIndex<_template->m_Patch.size(); patchIndex++)
{
AnimPatch *patch = &_template->m_Patch[patchIndex];
if (patch->m_nbPatchPoints!=0 &&
patch->m_AnimPatchPoints[0]->m_mainRefs.m_BonePtr == bone)
{
AABB patchBB;
u32 begin = pointListTmp1.size();
pointListTmp1.resize(begin + pathSize);
if (computePatchUVAABB(patch, patchBB, _image, &pointListTmp1[begin]))
{
if (isUVInit)
{
UVs.grow(patchBB);
}
else
{
UVs = patchBB;
isUVInit = btrue;
}
}
//
}
}
}
// now we recompute the pointList
i32 nbPatchs = pointListTmp1.size()/pathSize;
ITF_VECTOR<SegmentPatch> segmentList;
for (i32 i=0; i<nbPatchs; i++)
{
SegmentPatch spatch;
spatch.m_beginIndex = i*pathSize;
spatch.m_endIndex = i*pathSize + lineSize-1;
spatch.m_nextIndex = i*pathSize + pathSize-1;
segmentList.push_back(spatch);
spatch.m_beginIndex = i*pathSize + pathSize-1;
spatch.m_endIndex = i*pathSize + lineSize;
spatch.m_nextIndex = i*pathSize;
segmentList.push_back(spatch);
}
Vec2d posTab[2];
if (segmentList.size())
{
for (u32 i=0; i<segmentList.size()-1; i++)
{
posTab[0] = pointListTmp1[segmentList[i].m_endIndex];
posTab[1] = pointListTmp1[segmentList[i].m_nextIndex];
for (u32 posIdx=0; posIdx<2; posIdx++)
{
Vec2d & pos2 = posTab[posIdx];
u32 j;
for (j=i+1; j<segmentList.size(); j++)
{
if (pos2.IsEqual(pointListTmp1[segmentList[j].m_beginIndex], MTH_EPSILON))
{
SegmentPatch spatch = segmentList[j];
segmentList[j] = segmentList[i+1];
segmentList[i+1] = spatch;
break;
} else if (pos2.IsEqual(pointListTmp1[segmentList[j].m_endIndex], MTH_EPSILON))
{
SegmentPatch spatch = segmentList[j];
segmentList[j] = segmentList[i+1];
u32 swapIdx = spatch.m_beginIndex;
spatch.m_beginIndex = spatch.m_endIndex;
spatch.m_endIndex = swapIdx;
segmentList[i+1] = spatch;
break;
}
}
// no equal found next patch
if (j != segmentList.size())
break;
}
}
}
pointListTmp2.reserve(pointListTmp1.size());
for (u32 i=0; i<segmentList.size(); i++)
{
SegmentPatch &spatch = segmentList[i];
if (spatch.m_beginIndex < spatch.m_endIndex)
{
for (i32 j=spatch.m_beginIndex; j<=spatch.m_endIndex; j++)
if (!pointListTmp2.size() || !pointListTmp2[pointListTmp2.size()-1].IsEqual(pointListTmp1[j], MTH_EPSILON))
pointListTmp2.push_back(pointListTmp1[j]);
} else
{
for (i32 j=spatch.m_beginIndex; j>=spatch.m_endIndex; j--)
if (!pointListTmp2.size() || !pointListTmp2[pointListTmp2.size()-1].IsEqual(pointListTmp1[j], MTH_EPSILON))
pointListTmp2.push_back(pointListTmp1[j]);
}
}
m_processDelta = Vec2d::Zero;
m_pointList.resize(pointListTmp2.size());
for (u32 i=0; i<m_pointList.size(); i++)
{
m_pointList[i].x() = pointListTmp2[i].x()*(f32)m_initialImageWidth;
m_pointList[i].y() = pointListTmp2[i].y()*(f32)m_initialImageHeight;
if (m_processDelta.x() > m_pointList[i].x())
m_processDelta.x() = m_pointList[i].x();
if (m_processDelta.y() > m_pointList[i].y())
m_processDelta.y() = m_pointList[i].y();
}
for (u32 i=0; i<m_pointList.size(); i++)
{
m_pointList[i] -= m_processDelta;
}
int width = _image.width();
int height = _image.height();
//knowing we have bilinear filtering, we get every pixel concerned
UVs.setMin(UVs.getMin()*Vec2d((f32)width, (f32)height)-Vec2d(0.5f,0.5f));
UVs.setMax(UVs.getMax()*Vec2d((f32)width, (f32)height)+Vec2d(0.5f,0.5f));
m_UVBox.minx = (int)floorf(UVs.getMin().x());
m_UVBox.miny = (int)floorf(UVs.getMin().y());
m_UVBox.maxx = (int)ceilf(UVs.getMax().x());
m_UVBox.maxy = (int)ceilf(UVs.getMax().y());
}
void Patch::setSample( u32 _width, u32 _height, const SafeArray<u32> & _sampling )
{
m_widthSampling = _width;
m_heightSampling = _height;
m_sampling = _sampling;
}
}
}