diff --git a/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs b/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs index 1b2dba0f9..83d43b7da 100644 --- a/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs +++ b/spine-unity/Assets/spine-unity/Modules/SpriteAttacher.cs @@ -35,16 +35,21 @@ using Spine; namespace Spine.Unity.Modules { public class SpriteAttacher : MonoBehaviour { + const string DefaultPMAShader = "Spine/Skeleton"; + const string DefaultStraightAlphaShader = "Sprites/Default"; + + #region Inspector public bool attachOnStart = true; public bool keepLoaderInMemory = true; - public Sprite sprite; [SpineSlot] public string slot; + #endregion private SpriteAttachmentLoader loader; private RegionAttachment attachment; + private bool applyPMA; void Start () { if (attachOnStart) @@ -53,10 +58,11 @@ namespace Spine.Unity.Modules { public void Attach () { var skeletonRenderer = GetComponent(); + this.applyPMA = skeletonRenderer.pmaVertexColors; - if (loader == null) - //create loader instance, tell it what sprite and shader to use - loader = new SpriteAttachmentLoader(sprite, Shader.Find("Spine/Skeleton")); + Shader attachmentShader = applyPMA ? Shader.Find(DefaultPMAShader) : Shader.Find(DefaultStraightAlphaShader); + + loader = loader ?? new SpriteAttachmentLoader(sprite, attachmentShader, applyPMA); if (attachment == null) attachment = loader.NewRegionAttachment(null, sprite.name, ""); @@ -69,20 +75,16 @@ namespace Spine.Unity.Modules { } public class SpriteAttachmentLoader : AttachmentLoader { + //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck. + static public Dictionary atlasTable = new Dictionary(); - //MITCH: left a todo: Memory cleanup functions - - //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck. - public static Dictionary atlasTable = new Dictionary(); - - //Shouldn't need to clear this, should just prevent redoing premultiply alpha pass on packed atlases - public static List premultipliedAtlasIds = new List(); + static public List premultipliedAtlasIds = new List(); Sprite sprite; Shader shader; + //bool applyPMA; - public SpriteAttachmentLoader (Sprite sprite, Shader shader) { - + public SpriteAttachmentLoader (Sprite sprite, Shader shader, bool applyPMA) { if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight) { Debug.LogError("Tight Packer Policy not supported yet!"); return; @@ -90,32 +92,43 @@ namespace Spine.Unity.Modules { this.sprite = sprite; this.shader = shader; + //this.applyPMA = applyPMA; - Texture2D tex = sprite.texture; - //premultiply texture if it hasn't been yet - int instanceId = tex.GetInstanceID(); - if (!premultipliedAtlasIds.Contains(instanceId)) { + if (applyPMA) { try { - var colors = tex.GetPixels(); - Color c; - float a; - for (int i = 0; i < colors.Length; i++) { - c = colors[i]; - a = c.a; - c.r *= a; - c.g *= a; - c.b *= a; - colors[i] = c; + Texture2D texture = sprite.texture; + int instanceId = texture.GetInstanceID(); + if (!premultipliedAtlasIds.Contains(instanceId)) { + var colors = texture.GetPixels(); + Color c; + float a; + for (int i = 0; i < colors.Length; i++) { + c = colors[i]; + a = c.a; + c.r *= a; + c.g *= a; + c.b *= a; + colors[i] = c; + } + texture.SetPixels(colors); + texture.Apply(); + + premultipliedAtlasIds.Add(instanceId); } - - tex.SetPixels(colors); - tex.Apply(); - - premultipliedAtlasIds.Add(instanceId); } catch { - //texture is not readable! Can't pre-multiply it, you're on your own. + if (Application.isEditor) + Debug.LogWarning("Texture was not readable! Could not apply premultiply alpha. Rendering may be incorrect. Please check your texture import settings and make sure Read/Write is enabled."); } } + #if UNITY_EDITOR + else { + Texture2D texture = sprite.texture; + int instanceId = texture.GetInstanceID(); + if (premultipliedAtlasIds.Contains(instanceId)) + Debug.LogWarning("The same texture was used by both premultiply and straight alpha shaders. Rendering may be incorrect."); + } + #endif + } public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { @@ -124,11 +137,9 @@ namespace Spine.Unity.Modules { Texture2D tex = sprite.texture; int instanceId = tex.GetInstanceID(); AtlasRegion atlasRegion; + bool cachedMaterialExists = atlasTable.TryGetValue(instanceId, out atlasRegion); - // Check cache first - if (atlasTable.ContainsKey(instanceId)) { - atlasRegion = atlasTable[instanceId]; - } else { + if (!cachedMaterialExists) { // Setup new material. var material = new Material(shader); if (sprite.packed) @@ -139,7 +150,7 @@ namespace Spine.Unity.Modules { // Create faux-region to play nice with SkeletonRenderer. atlasRegion = new AtlasRegion(); - AtlasPage page = new AtlasPage(); + var page = new AtlasPage(); page.rendererObject = material; atlasRegion.page = page; @@ -149,16 +160,17 @@ namespace Spine.Unity.Modules { Rect texRect = sprite.textureRect; - //normalize rect to UV space of packed atlas + // Normalize rect to UV space of packed atlas texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x); texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y); texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width); texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height); Bounds bounds = sprite.bounds; - Vector3 size = bounds.size; + Vector2 boundsMin = bounds.min, boundsMax = bounds.max; + Vector2 size = bounds.size; + float spriteUnitsPerPixel = 1f / sprite.pixelsPerUnit; - //MITCH: left todo: make sure this rotation thing actually works bool rotated = false; if (sprite.packed) rotated = sprite.packingRotation == SpritePackingRotation.Any; @@ -168,8 +180,8 @@ namespace Spine.Unity.Modules { attachment.SetColor(Color.white); attachment.ScaleX = 1; attachment.ScaleY = 1; - attachment.RegionOffsetX = sprite.rect.width * (0.5f - InverseLerp(bounds.min.x, bounds.max.x, 0)) / sprite.pixelsPerUnit; - attachment.RegionOffsetY = sprite.rect.height * (0.5f - InverseLerp(bounds.min.y, bounds.max.y, 0)) / sprite.pixelsPerUnit; + attachment.RegionOffsetX = sprite.rect.width * (0.5f - InverseLerp(boundsMin.x, boundsMax.x, 0)) * spriteUnitsPerPixel; + attachment.RegionOffsetY = sprite.rect.height * (0.5f - InverseLerp(boundsMin.y, boundsMax.y, 0)) * spriteUnitsPerPixel; attachment.Width = size.x; attachment.Height = size.y; attachment.RegionWidth = size.x; @@ -182,7 +194,6 @@ namespace Spine.Unity.Modules { } public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { - //MITCH : Left todo: Unity 5 only return null; } @@ -194,21 +205,32 @@ namespace Spine.Unity.Modules { return null; } - private float InverseLerp(float a, float b, float value) - { + static float InverseLerp (float a, float b, float value) { return (value - a) / (b - a); } } public static class SpriteAttachmentExtensions { - public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton") { - var att = sprite.ToRegionAttachment(shaderName); + public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return skeleton.AttachUnitySprite(slotName, sprite, Shader.Find(shaderName), applyPMA); + } + + public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return skeletonData.AddUnitySprite(slotName, sprite, skinName, Shader.Find(shaderName), applyPMA); + } + + public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton", bool applyPMA = true) { + return sprite.ToRegionAttachment(Shader.Find(shaderName), applyPMA); + } + + public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, Shader shader, bool applyPMA) { + var att = sprite.ToRegionAttachment(shader, applyPMA); skeleton.FindSlot(slotName).Attachment = att; return att; } - public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton") { - var att = sprite.ToRegionAttachment(shaderName); + public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName, Shader shader, bool applyPMA) { + var att = sprite.ToRegionAttachment(shader, applyPMA); var slotIndex = skeletonData.FindSlotIndex(slotName); Skin skin = skeletonData.defaultSkin; @@ -220,8 +242,8 @@ namespace Spine.Unity.Modules { return att; } - public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton") { - var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); + public static RegionAttachment ToRegionAttachment (this Sprite sprite, Shader shader, bool applyPMA) { + var loader = new SpriteAttachmentLoader(sprite, shader, applyPMA); var att = loader.NewRegionAttachment(null, sprite.name, ""); loader = null; return att;