Exemple #1
0
	public PRRect Insert(int width, int height, ChoiceHeuristic method) 
	{
		PRRect newNode = new PRRect();
		int score1 = 0; // Unused in this function. We don't need to know the score after finding the position.
		int score2 = 0;

		switch(method) 
		{
			case ChoiceHeuristic.ShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
			case ChoiceHeuristic.BottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
			case ChoiceHeuristic.ContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break;
			case ChoiceHeuristic.LongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
			case ChoiceHeuristic.AreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
		}
		
		if (newNode.height == 0) return newNode;

		int numRectanglesToProcess = freeRectangles.Count;
		for(int i = 0; i < numRectanglesToProcess; ++i) 
		{
			if (SplitFreeNode(freeRectangles[i], ref newNode)) 
			{
				freeRectangles.RemoveAt(i);
				--i;
				--numRectanglesToProcess;
			}
		}
		
		PruneFreeList();
		
		usedRectangles.Add(newNode);
		return newNode;
	}
Exemple #2
0
    PRRect ScoreRect(int width, int height, ChoiceHeuristic method, ref int score1, ref int score2)
    {
        PRRect newNode = new PRRect();

        score1 = int.MaxValue;
        score2 = int.MaxValue;

        switch (method)
        {
        case ChoiceHeuristic.ShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;

        case ChoiceHeuristic.BottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;

        case ChoiceHeuristic.ContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1);
            score1 = -score1;             // Reverse since we are minimizing, but for contact point score bigger is better.
            break;

        case ChoiceHeuristic.LongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;

        case ChoiceHeuristic.AreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
        }

        // Cannot fit the current rectangle.
        if (newNode.height == 0)
        {
            score1 = int.MaxValue;
            score2 = int.MaxValue;
        }

        return(newNode);
    }
Exemple #3
0
    public void Insert(List <PRRect> rects, List <PRRect> dst, ChoiceHeuristic method)
    {
        dst.Clear();

        while (rects.Count > 0)
        {
            int    bestScore1    = int.MaxValue;
            int    bestScore2    = int.MaxValue;
            int    bestRectIndex = -1;
            PRRect bestNode      = new PRRect();

            for (int i = 0; i < rects.Count; ++i)
            {
                int    score1  = 0;
                int    score2  = 0;
                PRRect newNode = ScoreRect(rects[i].width, rects[i].height, method, ref score1, ref score2);

                if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2))
                {
                    bestScore1    = score1;
                    bestScore2    = score2;
                    bestNode      = newNode;
                    bestRectIndex = i;
                }
            }

            if (bestRectIndex == -1)
            {
                return;
            }

            PlaceRect(bestNode);
            rects.RemoveAt(bestRectIndex);
        }
    }
Exemple #4
0
	public PRRect Clone()
	{
		PRRect rect = new PRRect();
		rect.x = x;
		rect.y = y;
		rect.width = width;
		rect.height = height;
		return rect;
	}
Exemple #5
0
    public PRRect Clone()
    {
        PRRect rect = new PRRect();

        rect.x      = x;
        rect.y      = y;
        rect.width  = width;
        rect.height = height;
        return(rect);
    }
Exemple #6
0
    PRRect FindPositionForNewNodeBestAreaFit(int width, int height, ref int bestAreaFit, ref int bestShortSideFit)
    {
        PRRect bestNode = new PRRect();

        //memset(&bestNode, 0, sizeof(Rect));

        bestAreaFit = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            int areaFit = freeRectangles[i].width * freeRectangles[i].height - width * height;

            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int leftoverHoriz = Mathf.Abs(freeRectangles[i].width - width);
                int leftoverVert  = Mathf.Abs(freeRectangles[i].height - height);
                int shortSideFit  = Mathf.Min(leftoverHoriz, leftoverVert);

                if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x       = freeRectangles[i].x;
                    bestNode.y       = freeRectangles[i].y;
                    bestNode.width   = width;
                    bestNode.height  = height;
                    bestShortSideFit = shortSideFit;
                    bestAreaFit      = areaFit;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int leftoverHoriz = Mathf.Abs(freeRectangles[i].width - height);
                int leftoverVert  = Mathf.Abs(freeRectangles[i].height - width);
                int shortSideFit  = Mathf.Min(leftoverHoriz, leftoverVert);

                if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
                {
                    bestNode.x       = freeRectangles[i].x;
                    bestNode.y       = freeRectangles[i].y;
                    bestNode.width   = height;
                    bestNode.height  = width;
                    bestShortSideFit = shortSideFit;
                    bestAreaFit      = areaFit;
                }
            }
        }
        return(bestNode);
    }
Exemple #7
0
	public void Init(int width, int height) 
	{
		binWidth = width;
		binHeight = height;
		allowRotations = false;
		
		PRRect n = new PRRect();
		n.x = 0;
		n.y = 0;
		n.width = width;
		n.height = height;
		
		usedRectangles.Clear();
		
		freeRectangles.Clear();
		freeRectangles.Add(n);
	}
Exemple #8
0
    void PlaceRect(PRRect node)
    {
        int numRectanglesToProcess = freeRectangles.Count;

        for (int i = 0; i < numRectanglesToProcess; ++i)
        {
            if (SplitFreeNode(freeRectangles[i], ref node))
            {
                freeRectangles.RemoveAt(i);
                --i;
                --numRectanglesToProcess;
            }
        }

        PruneFreeList();

        usedRectangles.Add(node);
    }
Exemple #9
0
    public void Init(int width, int height)
    {
        binWidth       = width;
        binHeight      = height;
        allowRotations = false;

        PRRect n = new PRRect();

        n.x      = 0;
        n.y      = 0;
        n.width  = width;
        n.height = height;

        usedRectangles.Clear();

        freeRectangles.Clear();
        freeRectangles.Add(n);
    }
Exemple #10
0
    public PRRect Insert(int width, int height, ChoiceHeuristic method)
    {
        PRRect newNode = new PRRect();
        int    score1  = 0;     // Unused in this function. We don't need to know the score after finding the position.
        int    score2  = 0;

        switch (method)
        {
        case ChoiceHeuristic.ShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;

        case ChoiceHeuristic.BottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;

        case ChoiceHeuristic.ContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break;

        case ChoiceHeuristic.LongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;

        case ChoiceHeuristic.AreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
        }

        if (newNode.height == 0)
        {
            return(newNode);
        }

        int numRectanglesToProcess = freeRectangles.Count;

        for (int i = 0; i < numRectanglesToProcess; ++i)
        {
            if (SplitFreeNode(freeRectangles[i], ref newNode))
            {
                freeRectangles.RemoveAt(i);
                --i;
                --numRectanglesToProcess;
            }
        }

        PruneFreeList();

        usedRectangles.Add(newNode);
        return(newNode);
    }
Exemple #11
0
    PRRect FindPositionForNewNodeBottomLeft(int width, int height, ref int bestY, ref int bestX)
    {
        PRRect bestNode = new PRRect();

        //memset(bestNode, 0, sizeof(Rect));

        bestY = int.MaxValue;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int topSideY = freeRectangles[i].y + height;
                if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX))
                {
                    bestNode.x      = freeRectangles[i].x;
                    bestNode.y      = freeRectangles[i].y;
                    bestNode.width  = width;
                    bestNode.height = height;
                    bestY           = topSideY;
                    bestX           = freeRectangles[i].x;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int topSideY = freeRectangles[i].y + width;
                if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX))
                {
                    bestNode.x      = freeRectangles[i].x;
                    bestNode.y      = freeRectangles[i].y;
                    bestNode.width  = height;
                    bestNode.height = width;
                    bestY           = topSideY;
                    bestX           = freeRectangles[i].x;
                }
            }
        }
        return(bestNode);
    }
Exemple #12
0
    PRRect FindPositionForNewNodeContactPoint(int width, int height, ref int bestContactScore)
    {
        PRRect bestNode = new PRRect();

        //memset(&bestNode, 0, sizeof(Rect));

        bestContactScore = -1;

        for (int i = 0; i < freeRectangles.Count; ++i)
        {
            // Try to place the rectangle in upright (non-flipped) orientation.
            if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
            {
                int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, width, height);
                if (score > bestContactScore)
                {
                    bestNode.x       = freeRectangles[i].x;
                    bestNode.y       = freeRectangles[i].y;
                    bestNode.width   = width;
                    bestNode.height  = height;
                    bestContactScore = score;
                }
            }

            if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
            {
                int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, height, width);
                if (score > bestContactScore)
                {
                    bestNode.x       = freeRectangles[i].x;
                    bestNode.y       = freeRectangles[i].y;
                    bestNode.width   = height;
                    bestNode.height  = width;
                    bestContactScore = score;
                }
            }
        }
        return(bestNode);
    }
Exemple #13
0
	PRRect FindPositionForNewNodeBottomLeft(int width, int height, ref int bestY, ref int bestX) 
	{
		PRRect bestNode = new PRRect();
		//memset(bestNode, 0, sizeof(Rect));
		
		bestY = int.MaxValue;
		
		for(int i = 0; i < freeRectangles.Count; ++i) 
		{
			// Try to place the rectangle in upright (non-flipped) orientation.
			if (freeRectangles[i].width >= width && freeRectangles[i].height >= height)
			{
				int topSideY = freeRectangles[i].y + height;
				if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX)) 
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = width;
					bestNode.height = height;
					bestY = topSideY;
					bestX = freeRectangles[i].x;
				}
			}

			if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
			{
				int topSideY = freeRectangles[i].y + width;
				if (topSideY < bestY || (topSideY == bestY && freeRectangles[i].x < bestX)) 
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = height;
					bestNode.height = width;
					bestY = topSideY;
					bestX = freeRectangles[i].x;
				}
			}
		}
		return bestNode;
	}
Exemple #14
0
 bool IsContainedIn(PRRect a, PRRect b)
 {
     return(a.x >= b.x && a.y >= b.y &&
            a.x + a.width <= b.x + b.width &&
            a.y + a.height <= b.y + b.height);
 }
Exemple #15
0
    bool SplitFreeNode(PRRect freeNode, ref PRRect usedNode)
    {
        // Test with SAT if the rectangles even intersect.
        if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||
            usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)
        {
            return(false);
        }

        if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x)
        {
            // New node at the top side of the used node.
            if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height)
            {
                PRRect newNode = new PRRect();
                newNode.x      = freeNode.x;
                newNode.y      = freeNode.y;
                newNode.width  = freeNode.width;
                newNode.height = usedNode.y - newNode.y;
                freeRectangles.Add(newNode);
            }

            // New node at the bottom side of the used node.
            if (usedNode.y + usedNode.height < freeNode.y + freeNode.height)
            {
                PRRect newNode = new PRRect();
                newNode.x      = freeNode.x;
                newNode.y      = usedNode.y + usedNode.height;
                newNode.width  = freeNode.width;
                newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
                freeRectangles.Add(newNode);
            }
        }

        if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y)
        {
            // New node at the left side of the used node.
            if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width)
            {
                PRRect newNode = new PRRect();
                newNode.x      = freeNode.x;
                newNode.y      = freeNode.y;
                newNode.width  = usedNode.x - newNode.x;
                newNode.height = freeNode.height;
                freeRectangles.Add(newNode);
            }

            // New node at the right side of the used node.
            if (usedNode.x + usedNode.width < freeNode.x + freeNode.width)
            {
                PRRect newNode = new PRRect();
                newNode.x      = usedNode.x + usedNode.width;
                newNode.y      = freeNode.y;
                newNode.width  = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
                newNode.height = freeNode.height;
                freeRectangles.Add(newNode);
            }
        }

        return(true);
    }
Exemple #16
0
	bool SplitFreeNode(PRRect freeNode, ref PRRect usedNode) 
	{
		// Test with SAT if the rectangles even intersect.
		if (usedNode.x >= freeNode.x + freeNode.width || usedNode.x + usedNode.width <= freeNode.x ||
		    usedNode.y >= freeNode.y + freeNode.height || usedNode.y + usedNode.height <= freeNode.y)
			return false;
		
		if (usedNode.x < freeNode.x + freeNode.width && usedNode.x + usedNode.width > freeNode.x) 
		{
			// New node at the top side of the used node.
			if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.height) 
			{

				PRRect newNode = new PRRect();
				newNode.x = freeNode.x;
				newNode.y = freeNode.y;
				newNode.width = freeNode.width;
				newNode.height = usedNode.y - newNode.y;
				freeRectangles.Add(newNode);
			}
			
			// New node at the bottom side of the used node.
			if (usedNode.y + usedNode.height < freeNode.y + freeNode.height)
			{
				PRRect newNode = new PRRect();
				newNode.x = freeNode.x;
				newNode.y = usedNode.y + usedNode.height;
				newNode.width = freeNode.width;
				newNode.height = freeNode.y + freeNode.height - (usedNode.y + usedNode.height);
				freeRectangles.Add(newNode);
			}
		}
		
		if (usedNode.y < freeNode.y + freeNode.height && usedNode.y + usedNode.height > freeNode.y) 
		{
			// New node at the left side of the used node.
			if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.width) 
			{
				PRRect newNode = new PRRect();
				newNode.x = freeNode.x;
				newNode.y = freeNode.y;
				newNode.width = usedNode.x - newNode.x;
				newNode.height = freeNode.height;
				freeRectangles.Add(newNode);
			}
			
			// New node at the right side of the used node.
			if (usedNode.x + usedNode.width < freeNode.x + freeNode.width) 
			{
				PRRect newNode = new PRRect();
				newNode.x = usedNode.x + usedNode.width;
				newNode.y = freeNode.y;
				newNode.width = freeNode.x + freeNode.width - (usedNode.x + usedNode.width);
				newNode.height = freeNode.height;
				freeRectangles.Add(newNode);
			}
		}
		
		return true;
	}
Exemple #17
0
	PRRect FindPositionForNewNodeContactPoint(int width, int height, ref int bestContactScore) 
	{
		PRRect bestNode = new PRRect();
		//memset(&bestNode, 0, sizeof(Rect));
		
		bestContactScore = -1;
		
		for(int i = 0; i < freeRectangles.Count; ++i) 
		{
			// Try to place the rectangle in upright (non-flipped) orientation.
			if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 
			{
				int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, width, height);
				if (score > bestContactScore) 
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = width;
					bestNode.height = height;
					bestContactScore = score;
				}
			}

			if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width) 
			{
				int score = ContactPointScoreNode(freeRectangles[i].x, freeRectangles[i].y, height, width);
				if (score > bestContactScore) 
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = height;
					bestNode.height = width;
					bestContactScore = score;
				}
			}
		}
		return bestNode;
	}
Exemple #18
0
	PRRect ScoreRect(int width, int height, ChoiceHeuristic method, ref int score1, ref int score2) 
	{
		PRRect newNode = new PRRect();
		score1 = int.MaxValue;
		score2 = int.MaxValue;

		switch(method) 
		{
			case ChoiceHeuristic.ShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
			case ChoiceHeuristic.BottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
			case ChoiceHeuristic.ContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); 
			score1 = -score1; // Reverse since we are minimizing, but for contact point score bigger is better.
			break;
			case ChoiceHeuristic.LongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
			case ChoiceHeuristic.AreaFit: newNode = FindPositionForNewNodeBestAreaFit(width, height, ref score1, ref score2); break;
		}
		
		// Cannot fit the current rectangle.
		if (newNode.height == 0) 
		{
			score1 = int.MaxValue;
			score2 = int.MaxValue;
		}
		
		return newNode;
	}
    private void CalculateElementPacking()
    {
        int elementCount = elements.Count;

        //use the min area of all the elements to start with a sensible estimated size for the atlas to be
        int minArea = 0;

        for (int e = 0; e < elementCount; e++)
        {
            minArea += elements[e].expandedWidth * elements[e].expandedHeight;
        }

        int tryWidth  = 16;
        int tryHeight = 16;

        int tries = 0;

        while ((tryWidth - link.padding) * (tryHeight - link.padding) < minArea && tries++ < 100)
        {
            if (tries % 2 == 0)            //alternate increasing width and height until we find a size that fits everything
            {
                tryWidth *= 2;
            }
            else
            {
                tryHeight *= 2;
            }
        }

        tries = 0;

        //subtract padding because we can't pack right up to the padded border
        //but don't subtract padding*2 because the element sizes already account for padding on one side
        PRPacker packer = new PRPacker(tryWidth - link.padding, tryHeight - link.padding);

        while (tries++ < 100)        //tries is to prevent infinite loops
        {
            bool didFail = false;
            for (int e = 0; e < elementCount; e++)
            {
                PRAtlasElement element = elements[e];

                //Debug.Log("Try fitting " + element.expandedWidth + ", " + element.expandedHeight + " into " + tryWidth+","+tryHeight);
                //TODO update
                PRRect rect = packer.Insert(element.expandedWidth, element.expandedHeight, PRPacker.ChoiceHeuristic.ShortSideFit);

                if (rect.width == 0 && rect.height == 0)                //both at 0 means it failed
                {
                    didFail = true;

                    if (tryWidth <= tryHeight)                    //alternate increasing width and height until we find a size that fits everything
                    {
                        tryWidth *= 2;
                    }
                    else
                    {
                        tryHeight *= 2;
                    }

                    packer.Init(tryWidth - link.padding, tryHeight - link.padding);
                    break;
                }
                else
                {
                    element.packedRect    = rect;
                    element.packedRect.x += element.padding;                     //push the rect off the wall (note, y doesn't need this for the reason below)
                    //flip packing y coord. This is because the algorithm tries to pack everything around 0,0
                    //and we want 0,0 to be top left instead of bottom left (which it would be with Unity's coord system)
                    //there's no real reason for it to be top left, except that it's what people are used to.
                    element.packedRect.y = (tryHeight - element.packedRect.y) - element.packedRect.height;
                }
            }

            if (!didFail)
            {
                atlasWidth  = tryWidth;
                atlasHeight = tryHeight;
                break;                 //we're done!
            }
        }
    }
Exemple #20
0
	PRRect FindPositionForNewNodeBestAreaFit(int width, int height, ref int bestAreaFit, ref int bestShortSideFit) 
	{
		PRRect bestNode = new PRRect();
		//memset(&bestNode, 0, sizeof(Rect));
		
		bestAreaFit = int.MaxValue;
		
		for(int i = 0; i < freeRectangles.Count; ++i) 
		{
			int areaFit = freeRectangles[i].width * freeRectangles[i].height - width * height;
			
			// Try to place the rectangle in upright (non-flipped) orientation.
			if (freeRectangles[i].width >= width && freeRectangles[i].height >= height) 
			{
				int leftoverHoriz = Mathf.Abs(freeRectangles[i].width - width);
				int leftoverVert = Mathf.Abs(freeRectangles[i].height - height);
				int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
				
				if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit))
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = width;
					bestNode.height = height;
					bestShortSideFit = shortSideFit;
					bestAreaFit = areaFit;
				}
			}
			
			if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width) 
			{
				int leftoverHoriz = Mathf.Abs(freeRectangles[i].width - height);
				int leftoverVert = Mathf.Abs(freeRectangles[i].height - width);
				int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
				
				if (areaFit < bestAreaFit || (areaFit == bestAreaFit && shortSideFit < bestShortSideFit)) 
				{
					bestNode.x = freeRectangles[i].x;
					bestNode.y = freeRectangles[i].y;
					bestNode.width = height;
					bestNode.height = width;
					bestShortSideFit = shortSideFit;
					bestAreaFit = areaFit;
				}
			}
		}
		return bestNode;
	}
Exemple #21
0
	public void Insert(List<PRRect> rects, List<PRRect> dst, ChoiceHeuristic method) 
	{
		dst.Clear();
		
		while(rects.Count > 0)
		{
			int bestScore1 = int.MaxValue;
			int bestScore2 = int.MaxValue;
			int bestRectIndex = -1;
			PRRect bestNode = new PRRect();
			
			for(int i = 0; i < rects.Count; ++i) 
			{
				int score1 = 0;
				int score2 = 0;
				PRRect newNode = ScoreRect(rects[i].width, rects[i].height, method, ref score1, ref score2);
				
				if (score1 < bestScore1 || (score1 == bestScore1 && score2 < bestScore2)) 
				{
					bestScore1 = score1;
					bestScore2 = score2;
					bestNode = newNode;
					bestRectIndex = i;
				}
			}
			
			if (bestRectIndex == -1)
				return;
			
			PlaceRect(bestNode);
			rects.RemoveAt(bestRectIndex);
		}
	}
Exemple #22
0
	bool IsContainedIn(PRRect a, PRRect b) 
	{
		return a.x >= b.x && a.y >= b.y 
			&& a.x+a.width <= b.x+b.width 
			&& a.y+a.height <= b.y+b.height;
	}
    private IEnumerator <string> CreateAtlasTexture()
    {
        atlasTexture            = new Texture2D(atlasWidth, atlasHeight, TextureFormat.ARGB32, false);
        atlasTexture.filterMode = FilterMode.Bilinear;
        atlasTexture.SetPixels32(new Color32[atlasWidth * atlasHeight]);       //clear it out (using color32 for speed)

        int elementCount = elements.Count;

        for (int e = 0; e < elementCount; e++)
        {
            PRAtlasElement element = elements[e];

            yield return("Packing " + element.name);

            PRRect packedRect = element.packedRect;

            int extrude = element.extrude;

            int outputX      = packedRect.x + extrude;
            int outputY      = packedRect.y + extrude;
            int outputWidth  = packedRect.width - extrude * 2 - element.padding;
            int outputHeight = packedRect.height - extrude * 2 - element.padding;

            if (link.scale == 1.0f)
            {
                Color[] elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, element.sourceTrimWidth, element.sourceTrimHeight, 0);

                atlasTexture.SetPixels(outputX, outputY, outputWidth, outputHeight, elementPixels);
                //atlasTexture.SetPixels(outputX,outputY,outputWidth,outputHeight,elementPixels);

                if (extrude != 0)                //do extruding by pulling pixels from each edge
                {
                    //left
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, 1, element.sourceTrimHeight, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX - (c + 1), outputY, 1, outputHeight, elementPixels);
                    }

                    //right
                    elementPixels = element.texture.GetPixels(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY, 1, element.sourceTrimHeight, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX + outputWidth + c, outputY, 1, outputHeight, elementPixels);
                    }

                    //bottom
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, element.sourceTrimWidth, 1, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX, outputY - (c + 1), outputWidth, 1, elementPixels);
                    }

                    //top
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY + element.sourceTrimHeight - 1, element.sourceTrimWidth, 1, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX, outputY + outputHeight + c, outputWidth, 1, elementPixels);
                    }

                    //bottom left
                    Color[] cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX, element.sourceTrimY), extrude * extrude);
                    atlasTexture.SetPixels(outputX - extrude, outputY - extrude, extrude, extrude, cornerPixels);

                    //top left
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX, element.sourceTrimY + element.sourceTrimHeight - 1), extrude * extrude);
                    atlasTexture.SetPixels(outputX - extrude, outputY + outputHeight, extrude, extrude, cornerPixels);

                    //top right
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY + element.sourceTrimHeight - 1), extrude * extrude);
                    atlasTexture.SetPixels(outputX + outputWidth, outputY + outputHeight, extrude, extrude, cornerPixels);

                    //bottom right
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY), extrude * extrude);
                    atlasTexture.SetPixels(outputX + outputWidth, outputY - extrude, extrude, extrude, cornerPixels);
                }
            }
            else             //scale isn't 1, so do a bilinear resample of the texture into the atlas
            {
                /*
                 * Texture2D sourceTexture = element.texture;
                 *
                 * float ratioX = (1.0f / (float)element.sourceFullWidth);
                 * float ratioY = (1.0f / (float)element.sourceFullHeight);
                 *
                 * float trimX = ratioX * element.sourceTrimX;
                 * float trimY = ratioY * element.sourceTrimY;
                 */

                Texture2D sourceTexture = element.texture;

                Color[] outputPixels = new Color[outputWidth * outputHeight];

                float sourceRatioX = 1.0f / (float)element.sourceFullWidth;                 //the width of one pixel in uv coords
                float sourceRatioY = 1.0f / (float)element.sourceFullHeight;                //the height of one pixel in uv coords

                float trimPercentX      = sourceRatioX * (float)element.sourceTrimX;
                float trimPercentY      = sourceRatioY * (float)element.sourceTrimY;
                float trimPercentWidth  = sourceRatioX * (float)element.sourceTrimWidth;
                float trimPercentHeight = sourceRatioY * (float)element.sourceTrimHeight;

                trimPercentX += sourceRatioX * 0.5f;
                trimPercentY += sourceRatioY * 0.5f;

                trimPercentWidth  -= sourceRatioX * 1.0f;
                trimPercentHeight -= sourceRatioX * 1.0f;

                float outputRatioX = 1.0f / (float)(outputWidth - 1);
                float outputRatioY = 1.0f / (float)(outputHeight - 1);

                //Debug.Log(string.Format("{0} tpx:{1} tpy:{2} tpw:{3} tph:{4}",element.name,trimPercentX,trimPercentY,trimPercentWidth,trimPercentHeight));

                for (int r = 0; r < outputHeight; r++)
                {
                    for (int c = 0; c < outputWidth; c++)
                    {
                        float colPercent = (float)c * outputRatioX;
                        float rowPercent = (float)r * outputRatioY;

                        outputPixels[r * outputWidth + c] = sourceTexture.GetPixelBilinear(trimPercentX + colPercent * trimPercentWidth, trimPercentY + rowPercent * trimPercentHeight);

//
                        //multi sample with a kernel
//                      float bx = trimPercentX + colPercent*trimPercentWidth;
//						float by = trimPercentY + rowPercent*trimPercentHeight;
//
//						Color outputColor;
//
//						//outputColor = sourceTexture.GetPixelBilinear(baseX, baseY) * 0.7f;
//
//						float sx = sourceRatioX*(1.0f-link.scale);
//						float sy = sourceRatioY*(1.0f-link.scale);
//
//						float dsx = sx*2;
//						float dsy = sy*2;
//
//						float one = 1.0f/64.0f;
//						float three = 3.0f/64.0f;
//						float nine = 9.0f/64.0f;
//
//						//from https://groups.google.com/forum/#!topic/comp.graphics.algorithms/XpcOL2xiKO4
//
//						outputColor = sourceTexture.GetPixelBilinear(bx-dsx, by+dsy) * one;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by+dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by+dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by+dsy) * one;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by+sy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by+sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by+sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by+sy) * three;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by-sy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by-sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by-sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by-sy) * three;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by-dsy) * one;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by-dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by-dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by-dsy) * one;

//						outputColor = sourceTexture.GetPixelBilinear(bx, by) * 0.7f;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx, by+sourceRatioY) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx, by-sourceRatioY) * 0.05f;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by+sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by-sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by+sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by-sourceRatioY) * 0.0025f;
//
//						outputPixels[r*outputWidth + c] = outputColor;

                        //nearest neighbor
//						int pixelX = Mathf.RoundToInt((trimPercentX + colPercent*trimPercentWidth) * (float)sourceTexture.width);
//						int pixelY = Mathf.RoundToInt((trimPercentY + rowPercent*trimPercentHeight) * (float)sourceTexture.height);
//						outputPixels[r*outputWidth + c] = sourceTexture.GetPixel(pixelX,pixelY);
                    }
                }

                atlasTexture.SetPixels(outputX, outputY, outputWidth, outputHeight, outputPixels);

                if (element.extrude != 0)
                {
                    //yield return "Extruding " + element.name;

                    int heightExtruded = outputHeight + extrude * 2;

                    Color[] sidePixels = new Color[extrude * heightExtruded];                   //used for the left and right sides

                    //LEFT SIDE
                    for (int r = 0; r < heightExtruded; r++)                  //figure out row colour and then fill that row
                    {
                        int   outputRow = Mathf.Max(0, Mathf.Min(outputHeight - 1, r - extrude));
                        Color color     = outputPixels[outputRow * outputWidth];
                        for (int c = 0; c < extrude; c++)
                        {
                            sidePixels[r * extrude + c] = color;
                        }
                        atlasTexture.SetPixels(outputX - extrude, outputY - extrude, extrude, heightExtruded, sidePixels);
                    }

                    //RIGHT SIDE
                    for (int r = 0; r < heightExtruded; r++)                  //figure out row colour and then fill that row
                    {
                        int   outputRow = Mathf.Max(0, Mathf.Min(outputHeight - 1, r - extrude));
                        Color color     = outputPixels[outputRow * outputWidth + outputWidth - 1];
                        for (int c = 0; c < extrude; c++)
                        {
                            sidePixels[r * extrude + c] = color;
                        }
                        atlasTexture.SetPixels(outputX + outputWidth, outputY - extrude, extrude, heightExtruded, sidePixels);
                    }

                    sidePixels = new Color[extrude * outputWidth];                   //used for the top and bottom sides

                    //BOTTOM SIDE
                    for (int c = 0; c < outputWidth; c++)                  //figure out row colour and then fill that row
                    {
                        Color color = outputPixels[c];
                        for (int r = 0; r < extrude; r++)
                        {
                            sidePixels[r * outputWidth + c] = color;
                        }
                        atlasTexture.SetPixels(outputX, outputY - extrude, outputWidth, extrude, sidePixels);
                    }

                    //TOP SIDE
                    int topOffset = (outputHeight - 1) * outputWidth;      //start at the top row
                    for (int c = 0; c < outputWidth; c++)                  //figure out row colour and then fill that row
                    {
                        Color color = outputPixels[topOffset + c];
                        for (int r = 0; r < extrude; r++)
                        {
                            sidePixels[r * outputWidth + c] = color;
                        }
                        atlasTexture.SetPixels(outputX, outputY + outputHeight, outputWidth, extrude, sidePixels);
                    }
                }
            }
        }

//		int count = 5;
//		for(int i = 0; i < count; i++)
//		{
//			float percent = (float)i/(float)(count-1);
//			Debug.Log(i + " percent " + percent);
//		}

        yield return("Writing PNG to disk");

        atlasTexture.Apply(false, false);

        File.WriteAllBytes(link.atlasFilePath + pngSuffix, atlasTexture.EncodeToPNG());

        if (PRViewAtlasWindow.instance != null && PRViewAtlasWindow.instance.link == link)
        {
            PRViewAtlasWindow.instance.UpdateAtlas();
        }

        //in theory this should make it unreadable,
        //but it doesn't matter because we're about to delete it anyway
        //atlasTexture.Apply(false,true);



        //This stuff would be handy, but it's SO SLOW and unreliable that it's not worth it
//		TextureImporter importer = TextureImporter.GetAtPath(link.atlasFilePath+pngSuffix) as TextureImporter;
//
//		if(importer != null)
//		{
//			importer.maxTextureSize = Mathf.Max(importer.maxTextureSize,packedWidth,packedHeight);
//			importer.alphaIsTransparency = true;
//			AssetDatabase.ImportAsset(importer.assetPath);
//		}
//
//		yield return "Importing Atlas";
    }
Exemple #24
0
	void PlaceRect(PRRect node) 
	{
		int numRectanglesToProcess = freeRectangles.Count;

		for(int i = 0; i < numRectanglesToProcess; ++i) 
		{
			if (SplitFreeNode(freeRectangles[i], ref node)) 
			{
				freeRectangles.RemoveAt(i);
				--i;
				--numRectanglesToProcess;
			}
		}
		
		PruneFreeList();
		
		usedRectangles.Add(node);
	}