private static void CreateAtlasRaw() { var path = AssetDatabase.GetAssetPath(Selection.activeObject); path = string.IsNullOrEmpty(path) ? "Assets" : path; if (File.Exists(path)) { path = Path.GetDirectoryName(path); } var atlas = CreateInstance <AtlasRaw>(); atlas.bins = new BinRaw[0]; var setting = new PackSetting(); atlas.maxSize = setting.maxAtlasSize; atlas.padding = setting.padding; atlas.isPOT = setting.isPOT; atlas.forceSquare = setting.forceSquare; var assetPath = Path.Combine(path, PackConst.DefaultAtlasAssetName); assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath); atlas.id = PackUtil.GenerateAtlasId(); AssetDatabase.CreateAsset(atlas, assetPath); Selection.activeObject = AssetDatabase.LoadAssetAtPath <AtlasRaw>(assetPath); }
private void PackFolder(string folder) { var textures = AssetDatabase.FindAssets("t:Texture2D", new string[] { folder }) .Select(guid => AssetDatabase.GUIDToAssetPath(guid)) .Select(path => new PackAssetSprite(path)).ToArray(); if (textures.Length == 0) { return; } for (int i = 0; i < textures.Length; i++) { var texPath = textures[i].assetPath; var assetPath = texPath.Replace(folder + "/", ""); var assetDir = Path.GetDirectoryName(assetPath); var assetName = Path.GetFileNameWithoutExtension(assetPath); var assetLabel = string.IsNullOrEmpty(assetDir) ? assetName : assetDir + "/" + assetName; textures[i].name = assetLabel; textures[i].quality = PackUtil.CheckTextureCompressed(texPath) ? PackQuality.AlphaSplit : PackQuality.Full; } var atlasRaw = AtlasPacker.Pack(folder, textures, mSetting); if (atlasRaw != null) { Selection.activeObject = atlasRaw; } }
public static string[] Export(AtlasRaw atlas, SpriteRaw[] sprites, string folder) { var exportSprites = new string[sprites.Length]; var atlasSprites = sprites.Select(i => PackAtlasSprite.ParseSprite(atlas.bins[i.bin], i)).ToArray(); PackUtil.LoadAtlasTextures(atlasSprites); for (int i = 0; i < atlasSprites.Length; i++) { var sprite = atlasSprites[i]; var rect = sprite.rect; var texture = PackUtil.CreateBlankTexture((int)rect.width, (int)rect.height, sprite.transparency ? TextureFormat.RGBA32 : TextureFormat.RGB24); texture.SetPixels(sprite.Read()); var bytes = sprite.transparency ? texture.EncodeToPNG() : texture.EncodeToJPG(); var path = Path.Combine(folder, sprite.name) + (sprite.transparency ? ".png" : ".jpg"); var dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } File.WriteAllBytes(path, bytes); exportSprites[i] = path; if (EditorUtility.DisplayCancelableProgressBar("", "export: " + sprite.name, (float)i / sprites.Length)) { break; } } EditorUtility.ClearProgressBar(); AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); return(exportSprites); }
public PackAtlasSprite(BinRaw binRaw, SpriteRaw spriteRaw) { mMain = binRaw.main; Debug.Assert(mMain != null, "Can not find main texture."); mAddition = binRaw.addition; mName = spriteRaw.name; mRect = spriteRaw.rect; mBorder = spriteRaw.border; mPivot = spriteRaw.pivot; mTransparency = PackUtil.CheckAtlasBinTranparency(binRaw); mQuality = (PackQuality)binRaw.quality; }
public void Setup(PackSetting setting, BinRaw bin) { this.setting = setting; this.bin = bin; mainAsset = bin.main; mainAssetPath = AssetDatabase.GetAssetPath(mainAsset); mainImporter = AssetImporter.GetAtPath(mainAssetPath) as TextureImporter; if (bin.addition != null) { addAsset = bin.addition; addAssetPath = AssetDatabase.GetAssetPath(addAsset); addImporter = AssetImporter.GetAtPath(addAssetPath) as TextureImporter; } transparency = PackUtil.CheckAtlasBinTranparency(bin); maxTextureSize = PackUtil.Scale2POT(Mathf.Max((int)bin.size.x, (int)bin.size.y)); }
protected virtual void ProcessCommon() { mainImporter.isReadable = false; mainImporter.maxTextureSize = maxTextureSize; mainImporter.mipmapEnabled = false; mainImporter.wrapMode = TextureWrapMode.Clamp; mainImporter.npotScale = TextureImporterNPOTScale.None; mainImporter.textureCompression = TextureImporterCompression.Uncompressed; mainImporter.alphaIsTransparency = true; if (addImporter != null) { addImporter.isReadable = false; addImporter.maxTextureSize = PackUtil.Scale2POT(Mathf.Max(mainAsset.width, mainAsset.height)); addImporter.mipmapEnabled = false; addImporter.wrapMode = TextureWrapMode.Clamp; addImporter.npotScale = TextureImporterNPOTScale.None; addImporter.textureCompression = TextureImporterCompression.Uncompressed; addImporter.alphaIsTransparency = true; } }
public PackAssetSprite(string assetPath) { mAssetPath = assetPath; var sprite = mAssetPath.StartsWith("Assets/") ? AssetDatabase.LoadAssetAtPath <UnityEngine.Sprite>(mAssetPath) : null; if (sprite != null) { mBorder = sprite.border; mPivot = sprite.pivot; } else { mBorder = Vector4.zero; mPivot = new Vector2(0.5f, 0.5f); } mAsset = new Texture2D(1, 1); mAsset.LoadImage(File.ReadAllBytes(mAssetPath)); mName = Path.GetFileNameWithoutExtension(mAssetPath); mRect = new Rect(0, 0, mAsset.width, mAsset.height); mTransparency = PackUtil.CheckTextureTranparency(mAsset.format); mQuality = PackQuality.AlphaSplit; }
public AtlasRaw GenerateAtlas() { if (sprites.Length > PackConst.MaxNumberOfSpriteInAtlas) { Debug.LogError(string.Format("Sprites in excess of {0}.", PackConst.MaxNumberOfSpriteInAtlas)); return(null); } for (int i = 0; i < sprites.Length; i++) { var texName = sprites[i].name; var texRect = sprites[i].rect; if (texRect.width > setting.maxAtlasSize || texRect.height > setting.maxAtlasSize) { Debug.LogError(string.Format("Texture size should be lower than {0}: {1}.", setting.maxAtlasSize, texName)); return(null); } } var atlasSprites = sprites.Where(i => i is PackAtlasSprite).Select(i => i as PackAtlasSprite).ToArray(); PackUtil.LoadAtlasTextures(atlasSprites); var groups = sprites.GroupBy(texture => new { texture.quality, texture.transparency }) .OrderBy(group => group.Key.quality) .ThenBy(group => group.Key.transparency); var bins = groups.Select(group => { var groupQuality = group.Key.quality; var groupTransparency = group.Key.transparency; var groupSprites = group.ToArray(); var groupProcessor = PackProcessor.Fetch(groupQuality); groupProcessor.Setup(setting, groupSprites, groupTransparency); var groupBins = groupProcessor.Execute(); foreach (var groupBin in groupBins) { groupBin.quality = (int)groupQuality; } return(groupBins); }).SelectMany(i => i).ToArray(); for (int i = 0; i < bins.Length; i++) { foreach (var sprite in bins[i].sprites) { sprite.bin = i; } } var atlasRaw = AssetDatabase.LoadAssetAtPath <AtlasRaw>(atlasPath); var atlasExist = atlasRaw != null; if (atlasExist) { RemoveAtlasTextures(atlasRaw); } else { atlasRaw = ScriptableObject.CreateInstance <AtlasRaw>(); } atlasRaw.hideFlags = HideFlags.DontUnloadUnusedAsset; atlasRaw.bins = bins; atlasRaw.maxSize = setting.maxAtlasSize; atlasRaw.padding = setting.padding; atlasRaw.isPOT = setting.isPOT; atlasRaw.forceSquare = setting.forceSquare; if (atlasRaw.id == 0) { atlasRaw.id = PackUtil.GenerateAtlasId(); } CreateAtlasTextures(atlasRaw); if (atlasExist) { EditorUtility.SetDirty(atlasRaw); AssetDatabase.SaveAssets(); } else { AssetDatabase.CreateAsset(atlasRaw, atlasPath); } return(atlasRaw); }
private static void MapAtlas2Sprite(string targetFolder, List <UnityEngine.UI.Sprite> sprites) { var atlasRaw2AtlasFolder = new Dictionary <string, string>(); var atlasRaw2AtlasSprites = new Dictionary <string, Dictionary <string, string> >(); foreach (var sprite in sprites) { if (sprite != null && sprite.type == UnityEngine.UI.Sprite.Type.Atlas) { var path = AssetDatabase.GetAssetPath(sprite.atlasRaw); if (!string.IsNullOrEmpty(path)) { atlasRaw2AtlasFolder[path] = Path.Combine(targetFolder, Path.GetFileName(Path.GetDirectoryName(path))); atlasRaw2AtlasSprites[path] = new Dictionary <string, string>(); } } } foreach (var pair in atlasRaw2AtlasFolder) { var atlasPath = pair.Key; var targetPath = pair.Value; var atlasFolder = Path.GetDirectoryName(atlasPath); var atlasTag = Path.GetFileName(atlasFolder); var atlasRaw = AssetDatabase.LoadAssetAtPath <AtlasRaw>(atlasPath); var spriteRaws = atlasRaw.bins.SelectMany(i => i.sprites).ToArray(); var exportSprites = AtlasPacker.Export(atlasRaw, spriteRaws, targetPath); for (int i = 0; i < exportSprites.Length; i++) { atlasRaw2AtlasSprites[atlasPath][spriteRaws[i].name] = exportSprites[i]; var maxTextureSize = PackUtil.Scale2POT((int)Mathf.Max(spriteRaws[i].rect.width, spriteRaws[i].rect.height)); var binRaw = atlasRaw.bins[spriteRaws[i].bin]; var compressed = (PackQuality)binRaw.quality != PackQuality.Full; var tranparency = PackUtil.CheckAtlasBinTranparency(binRaw); var importer = (TextureImporter)AssetImporter.GetAtPath(exportSprites[i]); importer.textureType = TextureImporterType.Sprite; importer.spritePivot = spriteRaws[i].pivot; importer.spriteBorder = spriteRaws[i].border; importer.spritePackingTag = atlasTag; importer.isReadable = false; importer.maxTextureSize = maxTextureSize; importer.mipmapEnabled = false; importer.wrapMode = TextureWrapMode.Clamp; importer.npotScale = TextureImporterNPOTScale.None; importer.textureCompression = TextureImporterCompression.Uncompressed; importer.alphaIsTransparency = true; if (compressed) { importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "Standalone", overridden = true, maxTextureSize = maxTextureSize, compressionQuality = (int)TextureCompressionQuality.Normal, format = TextureImporterFormat.DXT5, }); importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "iPhone", overridden = true, maxTextureSize = maxTextureSize, compressionQuality = (int)TextureCompressionQuality.Normal, format = tranparency ? TextureImporterFormat.RGBA16 : TextureImporterFormat.RGB16, }); importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "Android", overridden = true, maxTextureSize = maxTextureSize, compressionQuality = (int)TextureCompressionQuality.Normal, format = tranparency ? TextureImporterFormat.ETC2_RGBA8 : TextureImporterFormat.ETC2_RGB4, }); } else { importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "Standalone", overridden = false, }); importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "iPhone", overridden = false, }); importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings() { name = "Android", overridden = false, }); } importer.SaveAndReimport(); } } for (int i = 0; i < sprites.Count; i++) { var sprite = sprites[i]; if (sprite != null && sprite.type == UnityEngine.UI.Sprite.Type.Atlas) { var atlasPath = AssetDatabase.GetAssetPath(sprite.atlasRaw); if (atlasRaw2AtlasSprites.ContainsKey(atlasPath)) { var atlasSprites = atlasRaw2AtlasSprites[atlasPath]; if (atlasSprites.ContainsKey(sprites[i].spriteName)) { var spritePath = atlasSprites[sprites[i].spriteName]; var unitySprite = AssetDatabase.LoadAssetAtPath <UnityEngine.Sprite>(spritePath); sprites[i] = new UnityEngine.UI.Sprite(unitySprite); } } } } }
private static void MapSprite2Atlas(string targetFolder, PackSetting setting, List <UnityEngine.UI.Sprite> sprites) { var spritePaths = new List <string>(); foreach (var sprite in sprites) { if (sprite != null && sprite.type == UnityEngine.UI.Sprite.Type.Sprite) { var path = AssetDatabase.GetAssetPath(sprite.sprite); if (!string.IsNullOrEmpty(path) && !spritePaths.Contains(path)) { spritePaths.Add(path); } } } var pathSpriteMap = new Dictionary <string, UnityEngine.UI.Sprite>(); var spriteGroups = spritePaths.GroupBy(path => { var importer = AssetImporter.GetAtPath(path) as TextureImporter; return(importer.spritePackingTag); }); foreach (var group in spriteGroups) { var groupPaths = group.ToArray(); var groupNames = Util.MapSpritePath2SpriteNameInAtlas(groupPaths); var groupSprites = new PackAssetSprite[groupPaths.Length]; for (int i = 0; i < groupPaths.Length; i++) { groupSprites[i] = new PackAssetSprite(groupPaths[i]) { name = groupNames[i] }; groupSprites[i].quality = PackUtil.CheckTextureCompressed(groupPaths[i]) ? PackQuality.AlphaSplit : PackQuality.Full; } var groupTag = string.IsNullOrEmpty(group.Key) ? EmptyTagName : group.Key; var groupFolder = Path.Combine(targetFolder, groupTag); if (!Directory.Exists(groupFolder)) { Directory.CreateDirectory(groupFolder); } var atlasRaw = AtlasPacker.Pack(groupFolder, groupSprites, setting); for (int i = 0; i < groupPaths.Length; i++) { pathSpriteMap[groupPaths[i]] = new UnityEngine.UI.Sprite(atlasRaw, groupNames[i]); } } ; for (int i = 0; i < sprites.Count; i++) { var sprite = sprites[i]; if (sprite != null && sprite.type == UnityEngine.UI.Sprite.Type.Sprite) { var path = AssetDatabase.GetAssetPath(sprite.sprite); if (!string.IsNullOrEmpty(path)) { sprites[i] = pathSpriteMap[path]; } } } }
public override void OnInspectorGUI() { OnValidateSelected(); var atlas = target as AtlasRaw; EditorGUILayout.GetControlRect(false, 2); int clickIndex = AtlasEditorUtil.TitleBar(new GUIContent[] { new GUIContent("+File"), new GUIContent("+Folder"), }); if (clickIndex == 0) { DisplayImportMenu(atlas, false); } else if (clickIndex == 1) { DisplayImportMenu(atlas, true); } mRepackFold = AtlasEditorUtil.ToggleBar(new GUIContent("Settings"), mRepackFold); if (mRepackFold) { if (!mPackDataInit) { mPackDataInit = true; mSetting = new PackSetting(atlas.maxSize, atlas.padding, atlas.isPOT, atlas.forceSquare); } EditorGUI.indentLevel += 1; mSetting.maxAtlasSize = EditorGUILayout.IntPopup("Max Size", mSetting.maxAtlasSize, Array.ConvertAll(PackConst.AtlasSizeList, value => value.ToString()), PackConst.AtlasSizeList); mSetting.padding = EditorGUILayout.IntField("Padding", mSetting.padding); mSetting.isPOT = EditorGUILayout.Toggle("Power Of 2", mSetting.isPOT); GUI.enabled = mSetting.isPOT; if (!mSetting.isPOT) { mSetting.forceSquare = false; } mSetting.forceSquare = EditorGUILayout.Toggle("Force Square", mSetting.forceSquare); GUI.enabled = true; var rect = EditorGUILayout.GetControlRect(false, 20); if (GUI.Button(new Rect(rect.center.x - 75, rect.y, 150, rect.height), "Repack")) { AtlasPacker.Repack(atlas, null, mSetting); } EditorGUI.indentLevel -= 1; EditorGUILayout.Space(); } EditorGUI.BeginChangeCheck(); mSearchPattern = AtlasEditorUtil.SearchBar(new GUIContent("Search Sprite"), mSearchPattern); if (EditorGUI.EndChangeCheck() || mAtlasDirty) { mSearchResults.Clear(); if (!string.IsNullOrEmpty(mSearchPattern)) { mSearchResults.AddRange(AtlasEditorUtil.SearchSprites(atlas, 0, mSearchPattern)); } } if (mAtlasDirty) { mAtlasDirty = false; mSelectedBin = Mathf.Clamp(mSelectedBin, 0, atlas.bins.Length - 1); mSelectedSprites.Clear(); } EditorGUI.indentLevel += 1; if (!string.IsNullOrEmpty(mSearchPattern)) { EditorGUILayout.LabelField(string.Format("{0} results", mSearchResults.Count)); } if (mSearchResults != null && mSearchResults.Count > 0) { OnValidateResult(); OnSearchResultGUI(); } EditorGUI.indentLevel -= 1; if (atlas.bins.Length > 0) { var titleRect = EditorGUILayout.GetControlRect(false, EditorStyles.toolbar.fixedHeight); var controlId = GUIUtility.GetControlID(FocusType.Passive); var eventType = Event.current.GetTypeForControl(controlId); if (eventType == EventType.Repaint) { EditorStyles.toolbar.Draw(titleRect, GUIContent.none, controlId); } var binNames = Array.ConvertAll(atlas.bins, i => PackUtil.GetDisplayName(i)); var binIndexes = new int[binNames.Length]; for (int i = 0; i < binNames.Length; i++) { binIndexes[i] = i; } mSelectedBin = EditorGUI.IntPopup(new Rect(10, titleRect.y, titleRect.width - 10, titleRect.height), "Preview Bin", mSelectedBin, binNames, binIndexes, EditorStyles.toolbarPopup); mSelectedBin = Mathf.Clamp(mSelectedBin, 0, atlas.bins.Length - 1); EditorGUILayout.Space(); var bin = atlas.bins[mSelectedBin]; var previewRect = EditorGUILayout.GetControlRect(false, 512); previewRect.width = Mathf.Min(previewRect.width, (float)bin.main.width / bin.main.height * previewRect.height); previewRect.height = (float)bin.main.height / bin.main.width * previewRect.width; OnPreviewBin(previewRect); } }
protected virtual BinRaw[] PackSprites(PackSetting setting, IPackSprite[] sprites) { var textures = sprites.Select(sprite => new Packer.Area((int)sprite.rect.width, (int)sprite.rect.height)).ToArray(); var spriteRaws = new List <SpriteRaw>(); var packers = new List <Packer>(); var sizeList = PackConst.AtlasSizeList; var maxSize = setting.maxAtlasSize; var padding = setting.padding; var isPOT = forcePowerOf2 || setting.isPOT; var forceSquare = this.forceSquare || setting.forceSquare; var index = 0; while (index < textures.Length) { var texArea = textures[index]; Packer.Rect texRect = null; for (int i = 0; i < packers.Count; i++) { var packer = packers[i]; while (true) { if (packer.Push(texArea, out texRect)) { spriteRaws.Add(new SpriteRaw() { bin = i, rect = new Rect(texRect.x, texRect.y, texRect.width, texRect.height), }); break; } var width = packer.bin.width; var height = packer.bin.height; if (forceSquare) { width *= 2; height *= 2; } else { if (width > height) { height *= 2; } else { width *= 2; } } if (width > maxSize || height > maxSize) { break; } packer.Extend(new Packer.Bin(width, height)); } if (texRect != null) { break; } } if (texRect == null) { packers.Add(new Packer(Packer.Algorithm.AdvancedHorizontalSkyline, new Packer.Bin(sizeList[0], sizeList[0]), padding)); } else { index += 1; } } var bins = new BinRaw[packers.Count]; for (int i = 0; i < packers.Count; i++) { bins[i] = new BinRaw(); bins[i].size = !isPOT && !forceSquare ? Vector2.zero : new Vector2(packers[i].bin.width, packers[i].bin.height); } if (!isPOT && !forceSquare) { for (int i = 0; i < spriteRaws.Count; i++) { var sprite = spriteRaws[i]; var bin = bins[sprite.bin]; bin.size = new Vector2( Mathf.Max(bin.size.x, sprite.rect.xMax), Mathf.Max(bin.size.y, sprite.rect.yMax)); } if (forceMultiplyOf4) { foreach (var bin in bins) { bin.size = new Vector2( Mathf.CeilToInt(bin.size.x / 4) * 4, Mathf.CeilToInt(bin.size.y / 4) * 4); } } } for (int i = 0; i < sprites.Length; i++) { var sprite = sprites[i]; var spriteRaw = spriteRaws[i]; spriteRaw.name = sprite.name.Replace("\\", "/"); spriteRaw.border = sprite.border; spriteRaw.pivot = sprite.pivot; var rect = spriteRaw.rect; var binRaw = bins[spriteRaw.bin]; binRaw.sprites = binRaw.sprites ?? new SpriteRaw[0]; Array.Resize(ref binRaw.sprites, binRaw.sprites.Length + 1); binRaw.sprites[binRaw.sprites.Length - 1] = spriteRaw; var main = binRaw.main; var add = binRaw.addition; var colors = sprite.Read(); if (main == null) { main = PackUtil.CreateBlankTexture((int)binRaw.size.x, (int)binRaw.size.y, !alphaSplit && transparency ? TextureFormat.RGBA32 : TextureFormat.RGB24); main.hideFlags = HideFlags.DontUnloadUnusedAsset; binRaw.main = main; } main.SetPixels( (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, colors); if (alphaSplit && transparency) { if (add == null) { add = PackUtil.CreateBlankTexture((int)binRaw.size.x, (int)binRaw.size.y, TextureFormat.RGB24); add.hideFlags = HideFlags.DontUnloadUnusedAsset; binRaw.addition = add; } for (int c = 0; c < colors.Length; c++) { colors[c] = new Color(colors[c].a, 0, 0); } add.SetPixels( (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, colors); } } return(bins); }