#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 & _sample, i32 x, i32 y, u32 _width, u32 _height, u32 fillidx) { const u32 maxSample = _width * _height; list 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 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 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= 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); } } } }