private void PackUVRects(ref Dictionary <int, Rect> a_rRectsToPackDict, out Dictionary <int, PackedRect> a_rPackedUVRectsDict, out int a_iAtlasWidth, out int a_iAtlasHeight) { bool bAllPacked; int iMaximumAtlasSize = (int)m_eMaximumAtlasSize; // Estimate atlas size for this loop Uni2DEditorTextureAtlasPacker.EstimateMinAtlasSize(a_rRectsToPackDict.Values, iMaximumAtlasSize, m_iPadding, out a_iAtlasWidth, out a_iAtlasHeight); Dictionary <int, Rect> oRectsToPackCopyDict = null; Uni2DEditorTextureAtlasPacker oPacker = new Uni2DEditorTextureAtlasPacker(a_iAtlasWidth, a_iAtlasHeight, m_iPadding, true); // Looking for best atlas size // Save infos about the best size we'll found Vector2 f2BestSize = new Vector2(a_iAtlasWidth, a_iAtlasHeight); Dictionary <int, PackedRect> rBestResultsOutput = null; Dictionary <int, Rect> rBestResultsInput = null; float fBestOccupancy = float.NegativeInfinity; // Breadth-first search data Queue <Vector2> oNextSizesToTest = new Queue <Vector2>( ); oNextSizesToTest.Enqueue(f2BestSize); while (oNextSizesToTest.Count != 0) { Vector2 f2AtlasSize = oNextSizesToTest.Dequeue( ); // Create a working copy of the input dictionary oRectsToPackCopyDict = new Dictionary <int, Rect>(a_rRectsToPackDict); // Reinit bin packer oPacker.Init((int)f2AtlasSize.x, (int)f2AtlasSize.y, m_iPadding, true); // Pack the most as possible with BSSF heuristic bAllPacked = oPacker.Insert(oRectsToPackCopyDict, Uni2DEditorTextureAtlasPacker.FreeRectChoiceHeuristic.RectBestShortSideFit); if (bAllPacked) { float fOccupancy = oPacker.Occupancy( ); // if better occupancy than current best or same occupancy and smaller surface area... if (fOccupancy > fBestOccupancy || (fOccupancy == fBestOccupancy && f2AtlasSize.sqrMagnitude < f2BestSize.sqrMagnitude)) { // New best f2BestSize = f2AtlasSize; fBestOccupancy = fOccupancy; rBestResultsOutput = oPacker.UsedRectangles; rBestResultsInput = oRectsToPackCopyDict; } } // Is tested atlas size is max? if (f2AtlasSize.x != iMaximumAtlasSize || f2AtlasSize.y != iMaximumAtlasSize) { // Add 2 sizes to test: doubled width & doubled height Vector2 f2AtlasDoubleWidthSize = new Vector2(Mathf.Min(f2AtlasSize.x * 2, iMaximumAtlasSize), f2AtlasSize.y); Vector2 f2AtlasDoubleHeightSize = new Vector2(f2AtlasSize.x, Mathf.Min(f2AtlasSize.y * 2, iMaximumAtlasSize)); // Ensure we don't enqueue these sizes twice if (f2AtlasSize != f2AtlasDoubleWidthSize && oNextSizesToTest.Contains(f2AtlasDoubleWidthSize) == false) { oNextSizesToTest.Enqueue(f2AtlasDoubleWidthSize); } // If sizes equal, it's a square => don't test doubled height or doubled width. // These cases are equal (double width square = flipped double height square) if (f2AtlasSize.x != f2AtlasSize.y && f2AtlasSize != f2AtlasDoubleHeightSize && oNextSizesToTest.Contains(f2AtlasDoubleHeightSize) == false) { oNextSizesToTest.Enqueue(f2AtlasDoubleHeightSize); } } else if (rBestResultsOutput == null) // Max square, no best results so far { // Set it as default best f2BestSize = f2AtlasSize; //fBestOccupancy = oPacker.Occupancy( ); // Won't be used rBestResultsOutput = oPacker.UsedRectangles; rBestResultsInput = oRectsToPackCopyDict; } oRectsToPackCopyDict = null; } a_rRectsToPackDict = rBestResultsInput; a_rPackedUVRectsDict = rBestResultsOutput; a_iAtlasWidth = (int)f2BestSize.x; a_iAtlasHeight = (int)f2BestSize.y; oPacker = null; }
private void PackUVRects( ref Dictionary<int, Rect> a_rRectsToPackDict, out Dictionary<int, PackedRect> a_rPackedUVRectsDict, out int a_iAtlasWidth, out int a_iAtlasHeight ) { bool bAllPacked; int iMaximumAtlasSize = (int) m_eMaximumAtlasSize; // Estimate atlas size for this loop Uni2DEditorTextureAtlasPacker.EstimateMinAtlasSize( a_rRectsToPackDict.Values, iMaximumAtlasSize, m_iPadding, out a_iAtlasWidth, out a_iAtlasHeight ); Dictionary<int, Rect> oRectsToPackCopyDict = null; Uni2DEditorTextureAtlasPacker oPacker = new Uni2DEditorTextureAtlasPacker( a_iAtlasWidth, a_iAtlasHeight, m_iPadding, true ); // Looking for best atlas size // Save infos about the best size we'll found Vector2 f2BestSize = new Vector2( a_iAtlasWidth, a_iAtlasHeight ); Dictionary<int, PackedRect> rBestResultsOutput = null; Dictionary<int, Rect> rBestResultsInput = null; float fBestOccupancy = float.NegativeInfinity; // Breadth-first search data Queue<Vector2> oNextSizesToTest = new Queue<Vector2>( ); oNextSizesToTest.Enqueue( f2BestSize ); while( oNextSizesToTest.Count != 0 ) { Vector2 f2AtlasSize = oNextSizesToTest.Dequeue( ); // Create a working copy of the input dictionary oRectsToPackCopyDict = new Dictionary<int, Rect>( a_rRectsToPackDict ); // Reinit bin packer oPacker.Init( (int) f2AtlasSize.x, (int) f2AtlasSize.y, m_iPadding, true ); // Pack the most as possible with BSSF heuristic bAllPacked = oPacker.Insert( oRectsToPackCopyDict, Uni2DEditorTextureAtlasPacker.FreeRectChoiceHeuristic.RectBestShortSideFit ); if( bAllPacked ) { float fOccupancy = oPacker.Occupancy( ); // if better occupancy than current best or same occupancy and smaller surface area... if( fOccupancy > fBestOccupancy || ( fOccupancy == fBestOccupancy && f2AtlasSize.sqrMagnitude < f2BestSize.sqrMagnitude ) ) { // New best f2BestSize = f2AtlasSize; fBestOccupancy = fOccupancy; rBestResultsOutput = oPacker.UsedRectangles; rBestResultsInput = oRectsToPackCopyDict; } } // Is tested atlas size is max? if( f2AtlasSize.x != iMaximumAtlasSize || f2AtlasSize.y != iMaximumAtlasSize ) { // Add 2 sizes to test: doubled width & doubled height Vector2 f2AtlasDoubleWidthSize = new Vector2( Mathf.Min( f2AtlasSize.x * 2, iMaximumAtlasSize ), f2AtlasSize.y ); Vector2 f2AtlasDoubleHeightSize = new Vector2( f2AtlasSize.x, Mathf.Min( f2AtlasSize.y * 2, iMaximumAtlasSize ) ); // Ensure we don't enqueue these sizes twice if( f2AtlasSize != f2AtlasDoubleWidthSize && oNextSizesToTest.Contains( f2AtlasDoubleWidthSize ) == false ) { oNextSizesToTest.Enqueue( f2AtlasDoubleWidthSize ); } // If sizes equal, it's a square => don't test doubled height or doubled width. // These cases are equal (double width square = flipped double height square) if( f2AtlasSize.x != f2AtlasSize.y && f2AtlasSize != f2AtlasDoubleHeightSize && oNextSizesToTest.Contains( f2AtlasDoubleHeightSize ) == false ) { oNextSizesToTest.Enqueue( f2AtlasDoubleHeightSize ); } } else if( rBestResultsOutput == null ) // Max square, no best results so far { // Set it as default best f2BestSize = f2AtlasSize; //fBestOccupancy = oPacker.Occupancy( ); // Won't be used rBestResultsOutput = oPacker.UsedRectangles; rBestResultsInput = oRectsToPackCopyDict; } oRectsToPackCopyDict = null; } a_rRectsToPackDict = rBestResultsInput; a_rPackedUVRectsDict = rBestResultsOutput; a_iAtlasWidth = (int) f2BestSize.x; a_iAtlasHeight = (int) f2BestSize.y; oPacker = null; }