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

559 lines
No EOL
14 KiB
C++

#include "stdafx.h"
#ifndef _PACKING_PATCH_H_
#include "AnimTexPacker/PackingPatch.h"
#endif //_PACKING_PATCH_H_
#ifndef _ITF_SEEDER_H_
#include "core/Seeder.h"
#endif //_ITF_SEEDER_H_
#ifndef _ITF_PACKEDTEXTUREAREA_H_
#include "AnimTexPacker/PackedTextureArea.h"
#endif //_ITF_PACKEDTEXTUREAREA_H_
namespace ITF
{
//*****************************************************************************
void seedFill(SafeArray<u32> & _sample, i32 x, i32 y, u32 _width, u32 _height, u32 fillidx)
{
const u32 maxSample = _width * _height;
list<Vec2d> liste_pixel;
i32 xCourant, yCourant, xVoisin, yVoisin;
Vec2d coordTemp;
coordTemp.x() = (f32)x;
coordTemp.y() = (f32)y;
liste_pixel.push_back(coordTemp);
while (!liste_pixel.empty())
{
// On traite le pixel courant
xCourant = (i32)(liste_pixel.front().x());
yCourant = (i32)(liste_pixel.front().y());
// Remplir le pixel courant du masque passé en paramétre
// (-1 : présent dans la file, 0 : vide, 1 : rempli)
//masque.m_masque[xCourant][yCourant] = 1;
i32 index = y * _width + x;
ITF_ASSERT(index < (i32)maxSample);
_sample[index] = fillidx+1;
// On ajoute les voisins
i32 xTab[4] = { xCourant , xCourant+1, xCourant , xCourant-1};
i32 yTab[4] = { yCourant-1, yCourant , yCourant+1, yCourant };
for (int ptIdx=0; ptIdx<4; ptIdx++)
{
xVoisin = xTab[ptIdx];
yVoisin = yTab[ptIdx];
if ( xVoisin >= 0 && xVoisin < (i32)_width && yVoisin >= 0 && yVoisin < (i32)_height)
{
u32 indexVoisin = yVoisin * _width + xVoisin;
// Note : attention, on utilise ici les propriétés du && parésseux !
u32 samplingVoisin = _sample[indexVoisin];
if (((samplingVoisin & SAMPLE_MASK) != fillidx) && (samplingVoisin != (fillidx+1)))
{
_sample[indexVoisin] = fillidx+1;
coordTemp.x() = (f32)xVoisin;
coordTemp.y() = (f32)yVoisin;
liste_pixel.push_back(coordTemp);
}
}
}
// On a fini de traiter le pixel courant on l'enléve de la liste
liste_pixel.pop_front();
}
}
//*****************************************************************************
//*****************************************************************************
PackingPatch::PackingPatch()
: m_area(0.0f)
, m_angle(0.0f)
, m_baryCenter(Vec2d::Zero)
, m_widthSampling(0)
, m_heightSampling(0)
, m_posInImage(Vec2d::Zero)
, m_rotateMode(ROTATE_0)
, m_rotation(0.0f)
, m_translation(Vec2d::Zero)
{
// none
}
//*****************************************************************************
PackingPatch::~PackingPatch()
{
// none
}
//*****************************************************************************
void PackingPatch::computeOBB(bbool _ignoreRotate)
{
f32 angleStep = MTH_PIBY2 / SAMPLE_ROTATE_OOBB;
Vec2d baryCenter = getBaryCenter();
f32 minArea = F32_INFINITY;
AABB minAABB(Vec2d::Zero, Vec2d::Zero);
f32 minAngle = 0.0f;
const u32 countPoints = m_points.size();
for (u32 i = 0; i < SAMPLE_ROTATE_OOBB; i++)
{
Vec2d min = Vec2d(F32_INFINITY, F32_INFINITY);
Vec2d max = Vec2d(-F32_INFINITY, -F32_INFINITY);
const f32 angle = angleStep * i;
// Rotate all points
for (u32 j = 0; j < countPoints; j++)
{
Vec2d point = m_points[j]; //copy
point = point.RotateAround(baryCenter, angle);
min.x() = Min(min.x(), point.x());
min.y() = Min(min.y(), point.y());
max.x() = Max(max.x(), point.x());
max.y() = Max(max.y(), point.y());
}
AABB aabb(min, max);
f32 area = aabb.getArea();
if (minArea > area)
{
minArea = area;
minAABB = aabb;
minAngle = angle;
}
if (_ignoreRotate)
break;
}
// Results
m_area = minArea;
m_angle = minAngle;
m_obb = minAABB;
m_baryCenter = baryCenter;
// Rotate def points
for (u32 j = 0; j < countPoints; j++)
{
Vec2d& point = m_points[j]; // Ref
point = point.RotateAround(m_baryCenter, m_angle);
}
// Move all in 0,0
for (u32 j = 0; j < countPoints; j++)
{
Vec2d& point = m_points[j];
point -= m_obb.getMin();
}
m_obb.moveCenter(m_obb.getCenter() - m_obb.getMin());
m_baryCenter -= m_obb.getMin();
}
//*****************************************************************************
bbool PackingPatch::isInside(f32 _gridSample, u32 fillIdx, u32 idxBegin, u32 idxEnd, u32 _x, u32 _y)
{
u32 indexRandom = _y * m_widthSampling + _x;
if ((m_sampling[indexRandom] & SAMPLE_MASK) == fillIdx)
{
return bfalse;
}
// Convert coord
f32 x = _x * _gridSample + (_gridSample * 0.5f) + m_obb.getMin().x();
f32 y = _y * _gridSample + (_gridSample * 0.5f) + m_obb.getMin().y();
Vec2d randPointA(0.0f, y);
Vec2d randPointB(x, y);
Vec2d res;
u32 countIntersec = 0;
for (u32 j = idxBegin; j < idxEnd; j++)
{
Vec2d& pointA = m_points[j];
Vec2d& pointB = m_points[j+1];
if (Segment_Segment(randPointA, randPointB, pointA, pointB, res, 0.0f))
countIntersec ++;
}
// last segment
Vec2d& pointA = m_points[idxEnd];
Vec2d& pointB = m_points[idxBegin];
if (Segment_Segment(randPointA, randPointB, pointA, pointB, res, 0.0f))
countIntersec ++;
return (countIntersec % 2) != 0;
}
void PackingPatch::sample(f32 _gridSample)
{
// Init sampling
m_widthSampling = (u32)ceil((f32)m_obb.getWidth() / _gridSample);
m_heightSampling = (u32)ceil((f32)m_obb.getHeight() / _gridSample);
m_sampling.resize(m_widthSampling * m_heightSampling);
memset(&m_sampling[0], 0, m_widthSampling * m_heightSampling *sizeof(u32));
SafeArray<u32> tmpSampling;
u32 tmpWidthSampling = m_widthSampling+2;
u32 tmpHeightSampling = m_heightSampling+2;
tmpSampling.resize(tmpWidthSampling*tmpHeightSampling);
const u32 countPoly = m_subPoly.size();
for (u32 polyIdx = 0; polyIdx < countPoly; polyIdx++)
{
u32 idxBegin = m_subPoly[polyIdx].m_begin;
u32 idxEnd = m_subPoly[polyIdx].m_end;
u32 fillIdx = 2*polyIdx+1;
if (idxEnd > idxBegin)
{
// Compute border
for (u32 j = idxBegin; j < idxEnd; j++)
{
Vec2d& pointA = m_points[j];
Vec2d& pointB = m_points[j+1];
gridFill(_gridSample, pointA, pointB, fillIdx);
}
Vec2d& pointA = m_points[idxEnd];
Vec2d& pointB = m_points[idxBegin];
gridFill(_gridSample, pointA, pointB, fillIdx);
memset(&tmpSampling[0], 0, tmpWidthSampling*tmpHeightSampling*sizeof(u32));
for (u32 yIdx=0; yIdx<m_heightSampling; yIdx++)
{
for (u32 xIdx=0; xIdx<m_widthSampling; xIdx++)
{
if ((m_sampling[xIdx + yIdx*m_widthSampling] & SAMPLE_MASK) == fillIdx)
tmpSampling[xIdx + 1 + (yIdx + 1)*tmpWidthSampling] = 1;
}
}
seedFill(tmpSampling, 0, 0, tmpWidthSampling, tmpHeightSampling, 1);
for (u32 yIdx=0; yIdx<m_heightSampling; yIdx++)
{
for (u32 xIdx=0; xIdx<m_widthSampling; xIdx++)
{
if (!tmpSampling[xIdx + 1 + (yIdx + 1)*tmpWidthSampling])
m_sampling[xIdx + yIdx*m_widthSampling] = fillIdx+1;
}
}
}
}
}
//*****************************************************************************
Vec2d PackingPatch::getBaryCenter()
{
const u32 countPoints = m_points.size();
Vec2d baryCenter = Vec2d::Zero;
for (u32 j = 0; j < countPoints; j++)
{
Vec2d& point = m_points[j];
baryCenter += point;
}
if (countPoints > 0)
{
baryCenter = baryCenter / (f32)countPoints;
}
return baryCenter;
}
//*****************************************************************************
//*****************************************************************************
void PackingPatch::getCoorSample(f32 _gridSample, const Vec2d & _pos, i32& _x, i32& _y)
{
_x = (i32)((_pos.x() - m_obb.getMin().x()) / _gridSample);
_y = (i32)((_pos.y() - m_obb.getMin().y()) / _gridSample);
_x = Clamp(_x, 0, (i32)(m_widthSampling - 1));
_y = Clamp(_y, 0, (i32)(m_heightSampling - 1));
}
//*****************************************************************************
void PackingPatch::fillPoint(i32 x, i32 y, u32 idx)
{
//(0: vide, 1: rempli)
//masque.m_masque[x][y] = 1;
u32 index = y * m_widthSampling + x;
ITF_ASSERT(index < m_widthSampling * m_heightSampling);
u32 mask = m_sampling[index] & SAMPLE_TAG;
if (m_sampling[index] != 0 && ((m_sampling[index] & SAMPLE_MASK) % 2) == 0)
mask |= SAMPLE_TAG;
m_sampling[index] = idx | mask;
}
void PackingPatch::bresenham(i32 x1, i32 y1, i32 x2, i32 y2, u32 idx)
{
const u32 maxSample = m_widthSampling * m_heightSampling;
i32 xa = x1;
i32 xb = x2;
i32 ya = y1;
i32 yb = y2;
int x,y,dx,dy,incrmX,incrmY,dp,NE,SE;
dx = xb-xa;
dy = yb-ya;
if (dx>0) {
incrmX = 1;
} else {
incrmX = -1;
dx *= -1;
}
if (dy>0){
incrmY = 1;
} else {
incrmY = -1;
dy *= -1;
}
if (dx>=dy) {
dp=2*dy-dx;
SE=2*dy;
NE=2*(dy-dx);
y=ya;
for(x=xa;x!=xb;x+=incrmX) {
fillPoint(x, y, idx);
if (dp<=0) { /* on choisit le pixel E */
dp += SE;
} else {
dp += NE;
y+=incrmY;
}
}
} else if (dx<dy) {
dp=2*dx-dy;
SE=2*dx;
NE=2*(dx-dy);
x=xa;
for(y=ya;y!=yb;y+=incrmY) {
fillPoint(x, y, idx);
if (dp<=0) { /* on choisit le pixel E */
dp += SE;
} else {
dp += NE;
x+=incrmX;
}
}
}
}
void PackingPatch::andres(i32 x1, i32 y1, i32 x2, i32 y2, u32 idx)
{
int i; // loop counter
int ystep, xstep; // the step on y and x axis
int error; // the error accumulated during the increment
int errorprev; // *vision the previous value of the error variable
int y = y1, x = x1; // the line points
int ddy, ddx; // compulsory variables: the double values of dy and dx
int dx = x2 - x1;
int dy = y2 - y1;
if (dy < 0)
{
ystep = -1;
dy = -dy;
}
else
{
ystep = 1;
}
if (dx < 0)
{
xstep = -1;
dx = -dx;
}
else
{
xstep = 1;
}
ddy = 2 * dy;
ddx = 2 * dx;
if (ddx >= ddy)
{
errorprev = error = dx;
for (i=0 ; i < dx ; i++)
{
x += xstep;
error += ddy;
if (error > ddx)
{
y += ystep;
error -= ddx;
if (error + errorprev < ddx)
{
fillPoint(x, y-ystep, idx);
}
else if (error + errorprev > ddx)
{
fillPoint(x-xstep, y, idx);
}
else
{
fillPoint(x-xstep, y, idx);
fillPoint(x, y-ystep, idx);
}
}
fillPoint(x, y, idx);
errorprev = error;
}
}
else
{
errorprev = error = dy;
for (i=0 ; i < dy ; i++)
{
y += ystep;
error += ddx;
if (error > ddy)
{
x += xstep;
error -= ddy;
if (error + errorprev < ddy)
{
fillPoint(x-xstep, y, idx);
}
else if (error + errorprev > ddy)
{
fillPoint(x, y-ystep, idx);
}
else
{
fillPoint(x-xstep, y, idx);
fillPoint(x, y-ystep, idx);
}
}
fillPoint(x, y, idx);
errorprev = error;
}
}
}
bbool Segment_Segment_Collinear(const Vec2d & _p1, const Vec2d & _p2, const Vec2d & _p3, const Vec2d & _p4)
{
// are vectors //
if (f32_Abs((_p2-_p1).cross(_p4-_p3)) > MTH_EPSILON)
return bfalse;
// are points collinear
if (f32_Abs((_p2-_p1).cross(_p4-_p1)) > MTH_EPSILON)
return bfalse;
// do point have common part
if ((_p3-_p1).dot(_p3-_p2) <= 0.f)
return btrue;
if ((_p4-_p1).dot(_p4-_p2) <= 0.f)
return btrue;
if ((_p1-_p3).dot(_p1-_p4) <= 0.f)
return btrue;
if ((_p2-_p3).dot(_p1-_p4) <= 0.f)
return btrue;
return bfalse;
}
void PackingPatch::gridFill( f32 _gridSample, Vec2d &_p1, Vec2d &_p2, u32 _idx )
{
i32 x1, x2, y1, y2;
getCoorSample(_gridSample, _p1, x1, y1);
getCoorSample(_gridSample, _p2, x2, y2);
if (x1 > x2)
{
i32 swap = x2;
x2 = x1;
x1 = swap;
}
if (y1 > y2)
{
i32 swap = y2;
y2 = y1;
y1 = swap;
}
Vec2d res;
Vec2d quad[4];
for (i32 y=y1; y<=y2; y++)
{
for (i32 x=x1; x<=x2; x++)
{
// check if x y cuts the line
quad[0] = Vec2d((f32)x, (f32)y ) * _gridSample + m_obb.getMin();
quad[1] = Vec2d((f32)x+1, (f32)y ) * _gridSample + m_obb.getMin();
quad[2] = Vec2d((f32)x, (f32)y+1) * _gridSample + m_obb.getMin();
quad[3] = Vec2d((f32)x+1, (f32)y+1) * _gridSample + m_obb.getMin();
bbool intersect = bfalse;
if (!intersect && (Segment_Segment(quad[0], quad[1], _p1, _p2, res, 0.0f) || Segment_Segment_Collinear(quad[0], quad[1], _p1, _p2)))
intersect = btrue;
if (!intersect && (Segment_Segment(quad[0], quad[2], _p1, _p2, res, 0.0f) || Segment_Segment_Collinear(quad[0], quad[2], _p1, _p2)))
intersect = btrue;
if (!intersect && (Segment_Segment(quad[3], quad[1], _p1, _p2, res, 0.0f) || Segment_Segment_Collinear(quad[3], quad[1], _p1, _p2)))
intersect = btrue;
if (!intersect && (Segment_Segment(quad[3], quad[2], _p1, _p2, res, 0.0f) || Segment_Segment_Collinear(quad[3], quad[2], _p1, _p2)))
intersect = btrue;
if (intersect)
fillPoint(x, y, _idx);
}
}
}
}