• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            l

            成都手游碼農(nóng)一枚
            隨筆 - 32, 文章 - 0, 評(píng)論 - 117, 引用 - 0
            數(shù)據(jù)加載中……

            [Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過(guò)大的問(wèn)題

            UGUI Image已Sprite為主,而簡(jiǎn)單的合并圖集可以使用自帶的SpritePacker。
            而當(dāng)在使用AssetBundle的時(shí)候情況有些不同,會(huì)造成每個(gè)AB都會(huì)引入完整的Sprite圖集,顯然就增加了AB的大小,重復(fù)資源。
            為了解決這個(gè)問(wèn)題我們可以手動(dòng)合并圖集,那么方案也有多種,這里我們可以編輯器自帶的API來(lái)實(shí)現(xiàn)一個(gè)小的圖集合并工具。
             private static bool CombineSpritesHelper(string path, string dpath, string name, int padding)
                
            {
                    
            string[] paths = AssetDatabase.FindAssets("t:sprite"new string[] { path });
                    List
            <Sprite> spriteList = new List<Sprite>();
                    List
            <Texture2D> texList = new List<Texture2D>();

                    
            foreach (var o in paths)
                    
            {
                        Sprite s 
            = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(o), typeof(Sprite)) as Sprite;
                        
            if (null != s)
                        
            {
                            spriteList.Add(s);
                            texList.Add(s.texture);
                        }

                    }


                    
            if (texList.Count > 0)
                    
            {
                        Texture2D tex 
            = new Texture2D(10241024, TextureFormat.ARGB32, true);
                        Rect[] uvs 
            = UITexturePacker.PackTextures(tex, texList.ToArray(), 44, padding, 1024);
                        
            if (null == uvs)
                        
            {
                            EditorUtility.DisplayDialog(path, 
            "圖集超過(guò)1024,需要分組成多張圖集""點(diǎn)擊退出");
                            Object.DestroyImmediate(tex);
                            tex 
            = null;
                            
            return false;
                        }

                        
            else
                        
            {
                            List
            <SpriteMetaData> metaList = new List<SpriteMetaData>();
                            
            for (int i = 0; i < uvs.Length; ++i)
                            
            {
                                SpriteMetaData data 
            = new SpriteMetaData();
                                data.alignment 
            = (int)SpriteAlignment.Center;
                                data.border 
            = spriteList[i].border;
                                data.name 
            = spriteList[i].name;
                                data.pivot 
            = spriteList[i].pivot;
                                data.rect 
            = new Rect(uvs[i].x * tex.width, uvs[i].y * tex.height, uvs[i].width * tex.width, uvs[i].height * tex.height);
                                metaList.Add(data);
                            }


                            
            //string dpath = path.Substring(0, path.Length - obj.name.Length) + "SpriteSet";
                            if (!System.IO.Directory.Exists(dpath))
                            
            {
                                System.IO.Directory.CreateDirectory(dpath);
                            }


                            
            string file = dpath + "/" + name + ".png";
                            
            if (System.IO.File.Exists(file))
                            
            {
                                System.IO.File.Delete(file);
                            }

                            System.IO.File.WriteAllBytes(file, tex.EncodeToPNG());

                            AssetDatabase.ImportAsset(file, ImportAssetOptions.ForceUpdate);
                            TextureImporter importer 
            = AssetImporter.GetAtPath(file) as TextureImporter;
                            importer.spritesheet 
            = metaList.ToArray();
                            importer.spriteImportMode 
            = SpriteImportMode.Multiple;
                            importer.textureType 
            = TextureImporterType.Sprite;
                            importer.textureFormat 
            = TextureImporterFormat.ARGB32;
                            importer.mipmapEnabled 
            = true;
                            importer.mipmapFilter 
            = TextureImporterMipFilter.BoxFilter;
                            importer.assetBundleName 
            = "ui_image/" + name.ToLower();
                            AssetDatabase.ImportAsset(file);
                            AssetDatabase.Refresh();
                        }

                    }

                    
            return true;
                }


                [MenuItem(
            "Tool/Combine Sprites")]
                [MenuItem(
            "Assets/Tool/Combine Sprites")]
                
            public static void CombineSprites()
                
            {
                    EditorUtility.DisplayProgressBar(
            "Combine Sprites""Initializing "0);
                    
            try
                    
            {
                        Object obj 
            = Selection.activeObject;
                        
            string path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
                        
            string dpath = path.Substring(0, path.Length - obj.name.Length) + "SpriteSet";

                        
            if (System.IO.Directory.Exists(path))
                        
            {
                            
            string[] directories = System.IO.Directory.GetDirectories(path);
                            
            int count = 0;
                            
            if (directories.Length > 0)
                            
            {
                                
            foreach (var directory in directories)
                                
            {
                                    count
            ++;
                                    EditorUtility.DisplayProgressBar(
            "Combine Sprites"string.Format("combing {0}", count), (float)(count) / (directories.Length));
                                    
            if (!CombineSpritesHelper(directory, dpath, string.Concat(obj.name, "_", count.ToString()), 1))
                                    
            {
                                        
            break;
                                    }

                                }

                            }

                            
            else
                            
            {
                                EditorUtility.DisplayProgressBar(
            "Combine Sprites""combing 0"1);
                                CombineSpritesHelper(path, dpath, obj.name, 
            1);
                            }

                        }

                    }

                    
            catch (System.Exception e)
                    
            {
                        Debug.LogError(e);
                    }

                    EditorUtility.ClearProgressBar();
                }

            使用方法很簡(jiǎn)單,可以修改源碼中的路徑,可以將多個(gè)Single Sprite合成一個(gè)Multi Sprite。然后在供,UGUI使用,注意最好保存好合并前的源文件,不然可能造成新增圖片打圖集后對(duì)應(yīng)不上從而造成引用丟失。

            補(bǔ)充UITextPacker.cs :引用自NGUI
            /*
                Based on the Public Domain MaxRectsBinPack.cpp source by Jukka Jylänki
                
            https://github.com/juj/RectangleBinPack/

                Ported to C# by Sven Magnus
                This version is also public domain - do whatever you want with it.
            */
            using UnityEngine;
            using System.Collections;
            using System.Collections.Generic;

            public class UITexturePacker
            {
                public int binWidth = 0;
                public int binHeight = 0;
                public bool allowRotations;

                public List<Rect> usedRectangles = new List<Rect>();
                public List<Rect> freeRectangles = new List<Rect>();

                public enum FreeRectChoiceHeuristic
                {
                    RectBestShortSideFit, ///< -BSSF: Positions the rectangle against the short side of a free rectangle into which it fits the best.
                    RectBestLongSideFit, ///< -BLSF: Positions the rectangle against the long side of a free rectangle into which it fits the best.
                    RectBestAreaFit, ///< -BAF: Positions the rectangle into the smallest free rect into which it fits.
                    RectBottomLeftRule, ///< -BL: Does the Tetris placement.
                    RectContactPointRule ///< -CP: Choosest the placement where the rectangle touches other rects as much as possible.
                };

                public UITexturePacker (int width, int height, bool rotations)
                {
                    Init(width, height, rotations);
                }

                public void Init (int width, int height, bool rotations)
                {
                    binWidth = width;
                    binHeight = height;
                    allowRotations = rotations;

                    Rect n = new Rect();
                    n.x = 0;
                    n.y = 0;
                    n.width = width;
                    n.height = height;

                    usedRectangles.Clear();

                    freeRectangles.Clear();
                    freeRectangles.Add(n);
                }

                private struct Storage
                {
                    public Rect rect;
                    public bool paddingX;
                    public bool paddingY;
                }

                public static Rect[] PackTextures (Texture2D texture, Texture2D[] textures, int width, int height, int padding, int maxSize)
                {
                    if (width > maxSize || height > maxSize) return null;
                    if (width > maxSize || height > maxSize) { int temp = width; width = height; height = temp; }
                    
                    // Force square by sizing up
                    /*
                    if (NGUISettings.forceSquareAtlas)
                    {
                        if (width > height)
                            height = width;
                        else if (height > width)
                            width = height;
                    }
                    
            */
                    UITexturePacker bp = new UITexturePacker(width, height, false);
                    Storage[] storage = new Storage[textures.Length];

                    for (int i = 0; i < textures.Length; i++)
                    {
                        Texture2D tex = textures[i];
                        if (!tex) continue;

                        Rect rect = new Rect();

                        int xPadding = 1;
                        int yPadding = 1;

                        for (xPadding = 1; xPadding >= 0; --xPadding)
                        {
                            for (yPadding = 1; yPadding >= 0; --yPadding)
                            {
                                rect = bp.Insert(tex.width + (xPadding * padding), tex.height + (yPadding * padding),
                                    UITexturePacker.FreeRectChoiceHeuristic.RectBestAreaFit);
                                if (rect.width != 0 && rect.height != 0) break;

                                // After having no padding if it still doesn't fit -- increase texture size.
                                else if (xPadding == 0 && yPadding == 0)
                                {
                                    return PackTextures(texture, textures, width * (width <= height ? 2 : 1),
                                        height * (height < width ? 2 : 1), padding, maxSize);
                                }
                            }
                            if (rect.width != 0 && rect.height != 0) break;
                        }

                        storage[i] = new Storage();
                        storage[i].rect = rect;
                        storage[i].paddingX = (xPadding != 0);
                        storage[i].paddingY = (yPadding != 0);
                    }

                    texture.Resize(width, height);
                    texture.SetPixels(new Color[width * height]);

                    // The returned rects
                    Rect[] rects = new Rect[textures.Length];

                    for (int i = 0; i < textures.Length; i++)
                    {
                        Texture2D tex = textures[i];
                        if (!tex) continue;

                        Rect rect = storage[i].rect;
                        int xPadding = (storage[i].paddingX ? padding : 0);
                        int yPadding = (storage[i].paddingY ? padding : 0);
                        Color[] colors = tex.GetPixels();

                        // Would be used to rotate the texture if need be.
                        if (rect.width != tex.width + xPadding)
                        {
                            Color[] newColors = tex.GetPixels();

                            for (int x = 0; x < rect.width; x++)
                            {
                                for (int y = 0; y < rect.height; y++)
                                {
                                    int prevIndex = ((int)rect.height - (y + 1)) + x * (int)tex.width;
                                    newColors[x + y * (int)rect.width] = colors[prevIndex];
                                }
                            }

                            colors = newColors;
                        }

                        texture.SetPixels((int)rect.x, (int)rect.y, (int)rect.width - xPadding, (int)rect.height - yPadding, colors);
                        rect.x /= width;
                        rect.y /= height;
                        rect.width = (rect.width - xPadding) / width;
                        rect.height = (rect.height - yPadding) / height;
                        rects[i] = rect;
                    }
                    texture.Apply();
                    return rects;
                }

                public Rect Insert (int width, int height, FreeRectChoiceHeuristic method)
                {
                    Rect newNode = new Rect();
                    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 FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
                        case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
                        case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1); break;
                        case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
                        case FreeRectChoiceHeuristic.RectBestAreaFit: 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;
                }

                public void Insert (List<Rect> rects, List<Rect> dst, FreeRectChoiceHeuristic method)
                {
                    dst.Clear();

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

                        for (int i = 0; i < rects.Count; ++i)
                        {
                            int score1 = 0;
                            int score2 = 0;
                            Rect newNode = ScoreRect((int)rects[i].width, (int)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);
                    }
                }

                void PlaceRect (Rect 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);
                }

                Rect ScoreRect (int width, int height, FreeRectChoiceHeuristic method, ref int score1, ref int score2)
                {
                    Rect newNode = new Rect();
                    score1 = int.MaxValue;
                    score2 = int.MaxValue;
                    switch (method)
                    {
                        case FreeRectChoiceHeuristic.RectBestShortSideFit: newNode = FindPositionForNewNodeBestShortSideFit(width, height, ref score1, ref score2); break;
                        case FreeRectChoiceHeuristic.RectBottomLeftRule: newNode = FindPositionForNewNodeBottomLeft(width, height, ref score1, ref score2); break;
                        case FreeRectChoiceHeuristic.RectContactPointRule: newNode = FindPositionForNewNodeContactPoint(width, height, ref score1);
                        score1 = -score1; // Reverse since we are minimizing, but for contact point score bigger is better.
                        break;
                        case FreeRectChoiceHeuristic.RectBestLongSideFit: newNode = FindPositionForNewNodeBestLongSideFit(width, height, ref score2, ref score1); break;
                        case FreeRectChoiceHeuristic.RectBestAreaFit: 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;
                }

                /// Computes the ratio of used surface area.
                public float Occupancy ()
                {
                    ulong usedSurfaceArea = 0;
                    for (int i = 0; i < usedRectangles.Count; ++i)
                        usedSurfaceArea += (uint)usedRectangles[i].width * (uint)usedRectangles[i].height;

                    return (float)usedSurfaceArea / (binWidth * binHeight);
                }

                Rect FindPositionForNewNodeBottomLeft (int width, int height, ref int bestY, ref int bestX)
                {
                    Rect bestNode = new Rect();
                    //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 = (int)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 = (int)freeRectangles[i].x;
                            }
                        }
                        if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
                        {
                            int topSideY = (int)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 = (int)freeRectangles[i].x;
                            }
                        }
                    }
                    return bestNode;
                }

                Rect FindPositionForNewNodeBestShortSideFit (int width, int height, ref int bestShortSideFit, ref int bestLongSideFit)
                {
                    Rect bestNode = new Rect();
                    //memset(&bestNode, 0, sizeof(Rect));

                    bestShortSideFit = 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 leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                            int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - height);
                            int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
                            int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);

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

                        if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
                        {
                            int flippedLeftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - height);
                            int flippedLeftoverVert = Mathf.Abs((int)freeRectangles[i].height - width);
                            int flippedShortSideFit = Mathf.Min(flippedLeftoverHoriz, flippedLeftoverVert);
                            int flippedLongSideFit = Mathf.Max(flippedLeftoverHoriz, flippedLeftoverVert);

                            if (flippedShortSideFit < bestShortSideFit || (flippedShortSideFit == bestShortSideFit && flippedLongSideFit < bestLongSideFit))
                            {
                                bestNode.x = freeRectangles[i].x;
                                bestNode.y = freeRectangles[i].y;
                                bestNode.width = height;
                                bestNode.height = width;
                                bestShortSideFit = flippedShortSideFit;
                                bestLongSideFit = flippedLongSideFit;
                            }
                        }
                    }
                    return bestNode;
                }

                Rect FindPositionForNewNodeBestLongSideFit (int width, int height, ref int bestShortSideFit, ref int bestLongSideFit)
                {
                    Rect bestNode = new Rect();
                    //memset(&bestNode, 0, sizeof(Rect));

                    bestLongSideFit = 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 leftoverHoriz = Mathf.Abs((int)freeRectangles[i].width - width);
                            int leftoverVert = Mathf.Abs((int)freeRectangles[i].height - height);
                            int shortSideFit = Mathf.Min(leftoverHoriz, leftoverVert);
                            int longSideFit = Mathf.Max(leftoverHoriz, leftoverVert);

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

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

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

                Rect FindPositionForNewNodeBestAreaFit (int width, int height, ref int bestAreaFit, ref int bestShortSideFit)
                {
                    Rect bestNode = new Rect();
                    //memset(&bestNode, 0, sizeof(Rect));

                    bestAreaFit = int.MaxValue;

                    for (int i = 0; i < freeRectangles.Count; ++i)
                    {
                        int areaFit = (int)freeRectangles[i].width * (int)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((int)freeRectangles[i].width - width);
                            int leftoverVert = Mathf.Abs((int)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((int)freeRectangles[i].width - height);
                            int leftoverVert = Mathf.Abs((int)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;
                }

                /// Returns 0 if the two intervals i1 and i2 are disjoint, or the length of their overlap otherwise.
                int CommonIntervalLength (int i1start, int i1end, int i2start, int i2end)
                {
                    if (i1end < i2start || i2end < i1start)
                        return 0;
                    return Mathf.Min(i1end, i2end) - Mathf.Max(i1start, i2start);
                }

                int ContactPointScoreNode (int x, int y, int width, int height)
                {
                    int score = 0;

                    if (x == 0 || x + width == binWidth)
                        score += height;
                    if (y == 0 || y + height == binHeight)
                        score += width;

                    for (int i = 0; i < usedRectangles.Count; ++i)
                    {
                        if (usedRectangles[i].x == x + width || usedRectangles[i].x + usedRectangles[i].width == x)
                            score += CommonIntervalLength((int)usedRectangles[i].y, (int)usedRectangles[i].y + (int)usedRectangles[i].height, y, y + height);
                        if (usedRectangles[i].y == y + height || usedRectangles[i].y + usedRectangles[i].height == y)
                            score += CommonIntervalLength((int)usedRectangles[i].x, (int)usedRectangles[i].x + (int)usedRectangles[i].width, x, x + width);
                    }
                    return score;
                }

                Rect FindPositionForNewNodeContactPoint (int width, int height, ref int bestContactScore)
                {
                    Rect bestNode = new Rect();
                    //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((int)freeRectangles[i].x, (int)freeRectangles[i].y, width, height);
                            if (score > bestContactScore)
                            {
                                bestNode.x = (int)freeRectangles[i].x;
                                bestNode.y = (int)freeRectangles[i].y;
                                bestNode.width = width;
                                bestNode.height = height;
                                bestContactScore = score;
                            }
                        }
                        if (allowRotations && freeRectangles[i].width >= height && freeRectangles[i].height >= width)
                        {
                            int score = ContactPointScoreNode((int)freeRectangles[i].x, (int)freeRectangles[i].y, height, width);
                            if (score > bestContactScore)
                            {
                                bestNode.x = (int)freeRectangles[i].x;
                                bestNode.y = (int)freeRectangles[i].y;
                                bestNode.width = height;
                                bestNode.height = width;
                                bestContactScore = score;
                            }
                        }
                    }
                    return bestNode;
                }

                bool SplitFreeNode (Rect freeNode, ref Rect 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)
                        {
                            Rect newNode = freeNode;
                            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)
                        {
                            Rect newNode = freeNode;
                            newNode.y = usedNode.y + usedNode.height;
                            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)
                        {
                            Rect newNode = freeNode;
                            newNode.width = usedNode.x - newNode.x;
                            freeRectangles.Add(newNode);
                        }

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

                    return true;
                }

                void PruneFreeList ()
                {
                    for (int i = 0; i < freeRectangles.Count; ++i)
                        for (int j = i + 1; j < freeRectangles.Count; ++j)
                        {
                            if (IsContainedIn(freeRectangles[i], freeRectangles[j]))
                            {
                                freeRectangles.RemoveAt(i);
                                --i;
                                break;
                            }
                            if (IsContainedIn(freeRectangles[j], freeRectangles[i]))
                            {
                                freeRectangles.RemoveAt(j);
                                --j;
                            }
                        }
                }

                bool IsContainedIn (Rect a, Rect 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;
                }
            }

            posted on 2015-12-09 17:19 l1989 閱讀(5417) 評(píng)論(2)  編輯 收藏 引用 所屬分類: 游戲

            評(píng)論

            # re: [Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過(guò)大的問(wèn)題  回復(fù)  更多評(píng)論   

            UITexturePacker沒(méi)有這個(gè)API
            2016-03-24 18:16 | mishimumu

            # re: [Unity3D] 5.0 圖集合并擴(kuò)展工具,用于解決UGUI與AssetBundle打包造成資源包過(guò)大的問(wèn)題  回復(fù)  更多評(píng)論   

            已經(jīng)補(bǔ)上了
            2016-05-17 13:37 | l1989
            狠狠干狠狠久久| 久久久久亚洲AV成人片| 亚洲AV乱码久久精品蜜桃| 2020久久精品国产免费| 伊人色综合久久天天| 精品久久久久久国产牛牛app| 国产高清国内精品福利99久久| 久久综合九色综合精品| 亚洲国产成人乱码精品女人久久久不卡| 日批日出水久久亚洲精品tv| 久久精品中文无码资源站| 久久国产免费观看精品3| 亚洲成人精品久久| 久久精品免费一区二区| 久久人人爽爽爽人久久久| 国产99久久久国产精品~~牛| 久久WWW免费人成一看片| 亚洲精品乱码久久久久久按摩| 国产激情久久久久影院老熟女免费| 久久人妻少妇嫩草AV蜜桃| 色综合久久综精品| 久久久久人妻一区精品色| 99久久做夜夜爱天天做精品| 国产精品伦理久久久久久| 狠狠干狠狠久久| 国产高潮久久免费观看| 国产激情久久久久影院老熟女免费| 人人狠狠综合久久88成人| 久久久久久国产a免费观看黄色大片 | 麻豆一区二区99久久久久| 久久久久久精品久久久久| 久久精品亚洲福利| 精品国产乱码久久久久久人妻 | 色欲av伊人久久大香线蕉影院| 亚洲精品无码久久久| 老司机午夜网站国内精品久久久久久久久| 久久久久免费看成人影片| 久久久91精品国产一区二区三区 | 久久久久久午夜成人影院| 精品综合久久久久久97超人| 中文字幕久久欲求不满|