[Unity3D] 5.0 图集合并扩展工具,用于解决UGUI与AssetBundle打包造成资源包过大的问题

xiaoxiao2021-02-28  16

http://www.cppblog.com/shly/archive/2015/12/09/212443.html

[Unity3D] 5.0 图集合并扩展工具,用于解决UGUI与AssetBundle打包造成资源包过大的问题

UGUI Image已Sprite为主,而简单的合并图集可以使用自带的SpritePacker。 而当在使用AssetBundle的时候情况有些不同,会造成每个AB都会引入完整的Sprite图集,显然就增加了AB的大小,重复资源。 为了解决这个问题我们可以手动合并图集,那么方案也有多种,这里我们可以编辑器自带的API来实现一个小的图集合并工具。   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(1024, 1024, TextureFormat.ARGB32, true);             Rect[] uvs = UITexturePacker.PackTextures(tex, texList.ToArray(), 4, 4, padding, 1024);             if (null == uvs)             {                 EditorUtility.DisplayDialog(path, "图集超过1024,需要分组成多张图集", "点击退出");                 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();     } 使用方法很简单,可以修改源码中的路径,可以将多个Single Sprite合成一个Multi Sprite。然后在供,UGUI使用,注意最好保存好合并前的源文件,不然可能造成新增图片打图集后对应不上从而造成引用丢失。 补充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;     } }

转载请注明原文地址: https://www.6miu.com/read-1100026.html

最新回复(0)