123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
- #if UNITY_EDITOR
- using System;
- using UnityEditor;
- using UnityEngine;
- #if UNITY_2D_SPRITE
- using UnityEditor.U2D.Sprites;
- #else
- #pragma warning disable CS0618 // Type or member is obsolete.
- #endif
- namespace Animancer.Editor.Tools
- {
- /// <summary>A wrapper around the '2D Sprite' package features for editing Sprite data.</summary>
- public class SpriteDataEditor
- {
- /************************************************************************************************************************/
- #if UNITY_2D_SPRITE
- /************************************************************************************************************************/
- private static SpriteDataProviderFactories _Factories;
- private static SpriteDataProviderFactories Factories
- {
- get
- {
- if (_Factories == null)
- {
- _Factories = new();
- _Factories.Init();
- }
- return _Factories;
- }
- }
- /************************************************************************************************************************/
- private readonly ISpriteEditorDataProvider Provider;
- private SpriteRect[] _SpriteRects;
- /************************************************************************************************************************/
- /// <summary>The number of sprites in the target data.</summary>
- public int SpriteCount
- {
- get => _SpriteRects.Length;
- set
- {
- Array.Resize(ref _SpriteRects, value);
- for (int i = 0; i < _SpriteRects.Length; i++)
- _SpriteRects[i] = new();
- }
- }
- /// <summary>Returns the name of the sprite at the specified `index`.</summary>
- public string GetName(int index) => _SpriteRects[index].name;
- /// <summary>Sets the name of the sprite at the specified `index`.</summary>
- public void SetName(int index, string name) => _SpriteRects[index].name = name;
- /// <summary>Returns the rect of the sprite at the specified `index`.</summary>
- public Rect GetRect(int index) => _SpriteRects[index].rect;
- /// <summary>Sets the rect of the sprite at the specified `index`.</summary>
- public void SetRect(int index, Rect rect) => _SpriteRects[index].rect = rect;
- /// <summary>Returns the pivot of the sprite at the specified `index`.</summary>
- public Vector2 GetPivot(int index) => _SpriteRects[index].pivot;
- /// <summary>Sets the pivot of the sprite at the specified `index`.</summary>
- public void SetPivot(int index, Vector2 pivot)
- {
- _SpriteRects[index].pivot = pivot;
- _SpriteRects[index].alignment = GetSpriteAlignment(pivot);
- }
- /// <summary>Returns the alignment of the sprite at the specified `index`.</summary>
- public SpriteAlignment GetAlignment(int index) => _SpriteRects[index].alignment;
- /// <summary>Sets the alignment of the sprite at the specified `index`.</summary>
- public void SetAlignment(int index, SpriteAlignment alignment) => _SpriteRects[index].alignment = alignment;
- /// <summary>Returns the border of the sprite at the specified `index`.</summary>
- public Vector4 GetBorder(int index) => _SpriteRects[index].border;
- /// <summary>Sets the border of the sprite at the specified `index`.</summary>
- public void SetBorder(int index, Vector4 border) => _SpriteRects[index].border = border;
- /************************************************************************************************************************/
- #else
- /************************************************************************************************************************/
- private SpriteMetaData[] _SpriteSheet;
- /************************************************************************************************************************/
- /// <summary>The number of sprites in the target data.</summary>
- public int SpriteCount
- {
- get => _SpriteSheet.Length;
- set => Array.Resize(ref _SpriteSheet, value);
- }
- /// <summary>Returns the name of the sprite at the specified `index`.</summary>
- public string GetName(int index) => _SpriteSheet[index].name;
- /// <summary>Sets the name of the sprite at the specified `index`.</summary>
- public void SetName(int index, string name) => _SpriteSheet[index].name = name;
- /// <summary>Returns the rect of the sprite at the specified `index`.</summary>
- public Rect GetRect(int index) => _SpriteSheet[index].rect;
- /// <summary>Sets the rect of the sprite at the specified `index`.</summary>
- public void SetRect(int index, Rect rect) => _SpriteSheet[index].rect = rect;
- /// <summary>Returns the pivot of the sprite at the specified `index`.</summary>
- public Vector2 GetPivot(int index) => _SpriteSheet[index].pivot;
- /// <summary>Sets the pivot of the sprite at the specified `index`.</summary>
- public void SetPivot(int index, Vector2 pivot)
- {
- _SpriteSheet[index].pivot = pivot;
- _SpriteSheet[index].alignment = (int)GetSpriteAlignment(pivot);
- }
- /// <summary>Returns the alignment of the sprite at the specified `index`.</summary>
- public SpriteAlignment GetAlignment(int index) => (SpriteAlignment)_SpriteSheet[index].alignment;
- /// <summary>Sets the alignment of the sprite at the specified `index`.</summary>
- public void SetAlignment(int index, SpriteAlignment alignment) => _SpriteSheet[index].alignment = (int)alignment;
- /// <summary>Returns the border of the sprite at the specified `index`.</summary>
- public Vector4 GetBorder(int index) => _SpriteSheet[index].border;
- /// <summary>Sets the border of the sprite at the specified `index`.</summary>
- public void SetBorder(int index, Vector4 border) => _SpriteSheet[index].border = border;
- /************************************************************************************************************************/
- #endif
- /************************************************************************************************************************/
- /// <summary>Returns the appropriate alignment for the given `pivot`.</summary>
- public static SpriteAlignment GetSpriteAlignment(Vector2 pivot)
- {
- switch (pivot.x)
- {
- case 0:
- switch (pivot.y)
- {
- case 0: return SpriteAlignment.BottomLeft;
- case 0.5f: return SpriteAlignment.LeftCenter;
- case 1: return SpriteAlignment.TopLeft;
- }
- break;
- case 0.5f:
- switch (pivot.y)
- {
- case 0: return SpriteAlignment.BottomCenter;
- case 0.5f: return SpriteAlignment.Center;
- case 1: return SpriteAlignment.TopCenter;
- }
- break;
- case 1:
- switch (pivot.y)
- {
- case 0: return SpriteAlignment.BottomRight;
- case 0.5f: return SpriteAlignment.RightCenter;
- case 1: return SpriteAlignment.TopRight;
- }
- break;
- }
- return SpriteAlignment.Custom;
- }
- /************************************************************************************************************************/
- private readonly TextureImporter Importer;
- /************************************************************************************************************************/
- /// <summary>Creates a new <see cref="SpriteDataEditor"/>.</summary>
- public SpriteDataEditor(TextureImporter importer)
- {
- Importer = importer;
- #if UNITY_2D_SPRITE
- Provider = Factories.GetSpriteEditorDataProviderFromObject(importer);
- Provider.InitSpriteEditorDataProvider();
- _SpriteRects = Provider.GetSpriteRects();
- #else
- _SpriteSheet = importer.spritesheet;
- #endif
- }
- /************************************************************************************************************************/
- /// <summary>Tries to find the index of the data matching the `sprite`.</summary>
- /// <remarks>
- /// Returns -1 if there is no data matching the <see cref="UnityEngine.Object.name"/>.
- /// <para></para>
- /// Returns -2 if there is more than one data matching the <see cref="UnityEngine.Object.name"/> but no
- /// <see cref="Sprite.rect"/> match.
- /// </remarks>
- public int IndexOf(Sprite sprite)
- {
- var nameMatchIndex = -1;
- var count = SpriteCount;
- for (int i = 0; i < count; i++)
- {
- if (GetName(i) == sprite.name)
- {
- if (GetRect(i) == sprite.rect)
- return i;
- if (nameMatchIndex == -1)// First name match.
- nameMatchIndex = i;
- else
- nameMatchIndex = -2;// Already found 2 name matches.
- }
- }
- if (nameMatchIndex == -1)
- {
- Debug.LogError($"No {nameof(SpriteMetaData)} for '{sprite.name}' was found.", sprite);
- }
- else if (nameMatchIndex == -2)
- {
- Debug.LogError($"More than one {nameof(SpriteMetaData)} for '{sprite.name}' was found" +
- $" but none of them matched the {nameof(Sprite)}.{nameof(Sprite.rect)}." +
- $" If the texture's Max Size is smaller than its actual size, increase the Max Size before performing this" +
- $" operation so that the {nameof(Rect)}s can be used to identify the correct data.", sprite);
- }
- return nameMatchIndex;
- }
- /************************************************************************************************************************/
- /// <summary>Logs an error and returns false if the data at the specified `index` is out of the texture bounds.</summary>
- public bool ValidateBounds(int index, Sprite sprite)
- {
- var rect = GetRect(index);
- if (rect.xMin >= 0 &&
- rect.yMin >= 0 &&
- rect.xMax <= sprite.texture.width &&
- rect.yMax <= sprite.texture.height)
- return true;
- var path = AssetDatabase.GetAssetPath(sprite);
- // The Max Texture Size import setting may cause the loaded texture to be smaller than the actual image.
- // Sprite dimensions are defined against the actual image though, so we need to check those bounds.
- var importer = (TextureImporter)AssetImporter.GetAtPath(path);
- importer.GetSourceTextureWidthAndHeight(out var width, out var height);
- if (rect.xMin >= 0 &&
- rect.yMin >= 0 &&
- rect.xMax <= width &&
- rect.yMax <= height)
- return true;
- Debug.LogError(
- $"This modification would put '{sprite.name}' at {rect}" +
- $" which is outside of the texture ({width}x{height})" +
- $" so '{path}' was not modified.",
- sprite);
- return false;
- }
- /************************************************************************************************************************/
- /// <summary>Applies any modifications to the target asset.</summary>
- public void Apply()
- {
- #if UNITY_2D_SPRITE
- Provider.SetSpriteRects(_SpriteRects);
- Provider.Apply();
- #else
- Importer.spritesheet = _SpriteSheet;
- EditorUtility.SetDirty(Importer);
- #endif
- Importer.SaveAndReimport();
- }
- /************************************************************************************************************************/
- }
- }
- #endif
|