You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			271 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			271 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C#
		
	
| namespace MagicaVoxelToolbox {
 | |
| 	using System.Collections.Generic;
 | |
| 	using System.Collections;
 | |
| 	using UnityEngine;
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public class PackingData {
 | |
| 
 | |
| 
 | |
| 		public int Width;
 | |
| 		public int Height;
 | |
| 		public Color[] TextureColors;
 | |
| 
 | |
| 
 | |
| 		public PackingData (int sizeU, int sizeV, Color[] colors, bool outline = true) {
 | |
| 			Width = sizeU;
 | |
| 			Height = sizeV;
 | |
| 			if (outline) {
 | |
| 				Width += 2;
 | |
| 				Height += 2;
 | |
| 			}
 | |
| 			TextureColors = new Color[Width * Height];
 | |
| 			if (outline) {
 | |
| 				for (int v = 1; v < Height - 1; v++) {
 | |
| 					TextureColors[v * Width] = colors[(v - 1) * sizeU];
 | |
| 					for (int u = 1; u < Width - 1; u++) {
 | |
| 						TextureColors[v * Width + u] = colors[(v - 1) * sizeU + (u - 1)];
 | |
| 					}
 | |
| 					TextureColors[v * Width + Width - 1] = colors[(v - 1) * sizeU + (Width - 3)];
 | |
| 
 | |
| 				}
 | |
| 				for (int u = 0; u < Width; u++) {
 | |
| 					TextureColors[u] = TextureColors[Width + u];
 | |
| 					TextureColors[(Height - 1) * Width + u] = TextureColors[(Height - 2) * Width + u];
 | |
| 				}
 | |
| 			} else {
 | |
| 				for (int v = 0; v < Height; v++) {
 | |
| 					for (int u = 0; u < Width; u++) {
 | |
| 						TextureColors[v * Width + u] = colors[v * sizeU + u];
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		public bool SameWith (PackingData other) {
 | |
| 			if (Width != other.Width || Height != other.Height) {
 | |
| 				return false;
 | |
| 			}
 | |
| 			int end = TextureColors.Length - Width;
 | |
| 			for (int i = Width; i < end; i++) {
 | |
| 				if (TextureColors[i] != other.TextureColors[i]) {
 | |
| 					return false;
 | |
| 				}
 | |
| 			}
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public struct RectPacking {
 | |
| 
 | |
| 
 | |
| 
 | |
| 		private class ItemSorter : IComparer<Item> {
 | |
| 			bool SortWithIndex;
 | |
| 			public ItemSorter (bool sortWithIndex) {
 | |
| 				SortWithIndex = sortWithIndex;
 | |
| 			}
 | |
| 			public int Compare (Item x, Item y) {
 | |
| 				return SortWithIndex ?
 | |
| 					x.Index.CompareTo(y.Index) :
 | |
| 					y.Height.CompareTo(x.Height);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		private struct Item {
 | |
| 			public int Index;
 | |
| 			public int X, Y;
 | |
| 			public int Width, Height;
 | |
| 			public Color[] TextureColors;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		private class Shelf {
 | |
| 
 | |
| 			public int Y;
 | |
| 			public int Width;
 | |
| 			public int Height;
 | |
| 			public int[] RoomHeight;
 | |
| 
 | |
| 
 | |
| 			public bool AddItem (ref Item item, ref int width, ref int height) {
 | |
| 
 | |
| 				int currentFitWidth = 0;
 | |
| 				int maxRoomY = 0;
 | |
| 				for (int i = 0; i < RoomHeight.Length; i++) {
 | |
| 					if (RoomHeight[i] >= item.Height) {
 | |
| 						// fit
 | |
| 						currentFitWidth++;
 | |
| 						maxRoomY = Mathf.Max(maxRoomY, Height - RoomHeight[i]);
 | |
| 						if (currentFitWidth >= item.Width) {
 | |
| 							item.Y = Y + maxRoomY;
 | |
| 							item.X = i - currentFitWidth + 1;
 | |
| 							// set width height
 | |
| 							width = Mathf.Max(width, item.X + item.Width);
 | |
| 							height = Mathf.Max(height, item.Y + item.Height);
 | |
| 							// Set room height
 | |
| 							for (int j = item.X; j < item.X + item.Width; j++) {
 | |
| 								RoomHeight[j] = Height - maxRoomY - item.Height;
 | |
| 							}
 | |
| 							return true;
 | |
| 						}
 | |
| 					} else {
 | |
| 						// not fit
 | |
| 						currentFitWidth = 0;
 | |
| 						maxRoomY = 0;
 | |
| 					}
 | |
| 				}
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 		public static Rect[] PackTextures (out Texture2D texture, List<PackingData> packingList, bool hasOutline, bool defaultClear) {
 | |
| 
 | |
| 			// Check
 | |
| 			if (packingList.Count == 0) {
 | |
| 				texture = Texture2D.whiteTexture;
 | |
| 				return new Rect[1] { new Rect(0, 0, 1, 1) };
 | |
| 			}
 | |
| 
 | |
| 			// Init
 | |
| 			int aimSize = 16;
 | |
| 			int minWidth = 16;
 | |
| 			int allArea = 0;
 | |
| 			List<Item> items = new List<Item>();
 | |
| 			for (int i = 0; i < packingList.Count; i++) {
 | |
| 				int w = packingList[i].Width;
 | |
| 				int h = packingList[i].Height;
 | |
| 				items.Add(new Item() {
 | |
| 					Index = i,
 | |
| 					Width = w,
 | |
| 					Height = h,
 | |
| 					TextureColors = packingList[i].TextureColors
 | |
| 				});
 | |
| 				allArea += items[i].Width * items[i].Height;
 | |
| 				minWidth = Mathf.Max(minWidth, items[i].Width);
 | |
| 			}
 | |
| 			while (aimSize < minWidth || aimSize * aimSize < allArea * 1.1f) {
 | |
| 				aimSize *= 2;
 | |
| 			}
 | |
| 
 | |
| 			//Sort With Height
 | |
| 			items.Sort(new ItemSorter(false));
 | |
| 
 | |
| 			// Pack
 | |
| 			int width = 0;
 | |
| 			int height = 0;
 | |
| 
 | |
| 			List<Shelf> shelfs = new List<Shelf>();
 | |
| 			for (int i = 0; i < items.Count; i++) {
 | |
| 
 | |
| 				// Try Add
 | |
| 				bool success = false;
 | |
| 				Item item = items[i];
 | |
| 				for (int j = 0; j < shelfs.Count; j++) {
 | |
| 					success = shelfs[j].AddItem(
 | |
| 						ref item, ref width, ref height
 | |
| 					);
 | |
| 					if (success) {
 | |
| 						items[i] = item;
 | |
| 						break;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				// Fail to Add
 | |
| 				if (!success) {
 | |
| 
 | |
| 					// New shelf
 | |
| 					Shelf s = new Shelf() {
 | |
| 						Y = shelfs.Count == 0 ? 0 : shelfs[shelfs.Count - 1].Y + shelfs[shelfs.Count - 1].Height,
 | |
| 						Width = aimSize,
 | |
| 						Height = items[i].Height,
 | |
| 						RoomHeight = new int[aimSize],
 | |
| 					};
 | |
| 					for (int j = 0; j < aimSize; j++) {
 | |
| 						s.RoomHeight[j] = s.Height;
 | |
| 					}
 | |
| 					shelfs.Add(s);
 | |
| 
 | |
| 					// Add Again
 | |
| 					success = shelfs[shelfs.Count - 1].AddItem(
 | |
| 						ref item, ref width, ref height
 | |
| 					);
 | |
| 					items[i] = item;
 | |
| 
 | |
| 					// Error, this shouldn't be happen...
 | |
| 					if (!success) {
 | |
| 						throw new System.Exception("Fail to pack textures.");
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 			// Set Texture
 | |
| 			width = aimSize;
 | |
| 			height = Mathf.Max(height, aimSize);
 | |
| 			texture = new Texture2D(width, height, TextureFormat.ARGB32, false, false) {
 | |
| 				filterMode = FilterMode.Point
 | |
| 			};
 | |
| 
 | |
| 			// Default Color
 | |
| 			if (defaultClear) {
 | |
| 				var defualtColors = new Color[width * height];
 | |
| 				for (int i = 0; i < defualtColors.Length; i++) {
 | |
| 					defualtColors[i] = Color.clear;
 | |
| 				}
 | |
| 				texture.SetPixels(defualtColors);
 | |
| 			}
 | |
| 
 | |
| 
 | |
| 			for (int i = 0; i < items.Count; i++) {
 | |
| 				texture.SetPixels(
 | |
| 					items[i].X,
 | |
| 					items[i].Y,
 | |
| 					items[i].Width,
 | |
| 					items[i].Height,
 | |
| 					items[i].TextureColors
 | |
| 				);
 | |
| 			}
 | |
| 			texture.Apply();
 | |
| 
 | |
| 			// Sort with Index
 | |
| 			items.Sort(new ItemSorter(true));
 | |
| 			Rect[] uvs = new Rect[items.Count];
 | |
| 			for (int i = 0; i < items.Count; i++) {
 | |
| 				if (hasOutline) {
 | |
| 					uvs[i] = new Rect(
 | |
| 						(float)(items[i].X + 1) / width,
 | |
| 						(float)(items[i].Y + 1) / height,
 | |
| 						(float)(items[i].Width - 2) / width,
 | |
| 						(float)(items[i].Height - 2) / height
 | |
| 					);
 | |
| 				} else {
 | |
| 					uvs[i] = new Rect(
 | |
| 						(float)(items[i].X) / width,
 | |
| 						(float)(items[i].Y) / height,
 | |
| 						(float)(items[i].Width) / width,
 | |
| 						(float)(items[i].Height) / height
 | |
| 					);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return uvs;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 	}
 | |
| }
 |