From f73d6e5d1c194d02f040ea9edafed88b11171378 Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 13 Mar 2015 20:15:01 -0700 Subject: [PATCH 1/3] SpriteAttachmentLoader and friends --- .../Assets/spine-unity/SkeletonExtensions.cs | 31 ++++ .../Assets/spine-unity/SpriteAttacher.cs | 168 ++++++++++++++++++ .../Assets/spine-unity/SpriteAttacher.cs.meta | 8 + 3 files changed, 207 insertions(+) create mode 100644 spine-unity/Assets/spine-unity/SpriteAttacher.cs create mode 100644 spine-unity/Assets/spine-unity/SpriteAttacher.cs.meta diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index e1dad6e58..e4d4a35fc 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -105,4 +105,35 @@ public static class SkeletonExtensions { bone.Y = position.y; } + public static void AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton") { + var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); + + var att = loader.NewRegionAttachment(null, sprite.name, ""); + skeleton.FindSlot(slotName).Attachment = att; + + loader = null; + } + + public static void AddUnitySprite(this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton"){ + var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); + var att = loader.NewRegionAttachment(null, sprite.name, ""); + + var slotIndex = skeletonData.FindSlotIndex(slotName); + Skin skin = skeletonData.defaultSkin; + if(skinName != "") + skin = skeletonData.FindSkin(skinName); + + + skin.AddAttachment(slotIndex, att.Name, att); + + loader = null; + } + + public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton") { + var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); + var att = loader.NewRegionAttachment(null, sprite.name, ""); + loader = null; + return att; + } + } \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SpriteAttacher.cs b/spine-unity/Assets/spine-unity/SpriteAttacher.cs new file mode 100644 index 000000000..1c79423fc --- /dev/null +++ b/spine-unity/Assets/spine-unity/SpriteAttacher.cs @@ -0,0 +1,168 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Spine; + +public class SpriteAttacher : MonoBehaviour { + + + public bool attachOnStart = true; + public bool keepLoaderInMemory = true; + + public Sprite sprite; + + [SpineSlot] + public string slot; + + private SpriteAttachmentLoader loader; + private RegionAttachment attachment; + + void Start () { + if (attachOnStart) + Attach(); + } + + public void Attach () { + var skeletonRenderer = GetComponent(); + + if(loader == null) + //create loader instance, tell it what sprite and shader to use + loader = new SpriteAttachmentLoader(sprite, Shader.Find("Spine/Skeleton")); + + if(attachment == null) + attachment = loader.NewRegionAttachment(null, sprite.name, ""); + + skeletonRenderer.skeleton.FindSlot(slot).Attachment = attachment; + + if (!keepLoaderInMemory) + loader = null; + } +} + +public class SpriteAttachmentLoader : AttachmentLoader { + + //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(); + + Sprite sprite; + Shader shader; + + public SpriteAttachmentLoader (Sprite sprite, Shader shader) { + + if (sprite.packingMode == SpritePackingMode.Tight) { + Debug.LogError("Tight Packer Policy not supported yet!"); + return; + } + + this.sprite = sprite; + this.shader = shader; + + Texture2D tex = sprite.texture; + //premultiply texture if it hasn't been yet + int instanceId = tex.GetInstanceID(); + if (!premultipliedAtlasIds.Contains(instanceId)) { + 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; + } + + tex.SetPixels(colors); + tex.Apply(); + + premultipliedAtlasIds.Add(instanceId); + } catch { + //texture is not readable! Can't pre-multiply it, you're on your own. + } + } + } + + public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { + RegionAttachment attachment = new RegionAttachment(name); + + Texture2D tex = sprite.texture; + int instanceId = tex.GetInstanceID(); + AtlasRegion atlasRegion; + + //check cache first + if (atlasTable.ContainsKey(instanceId)) { + atlasRegion = atlasTable[instanceId]; + } else { + //Setup new material + Material mat = new Material(shader); + if(sprite.packed) + mat.name = "Unity Packed Sprite Material"; + else + mat.name = sprite.name + " Sprite Material"; + mat.mainTexture = tex; + + //create faux-region to play nice with SkeletonRenderer + atlasRegion = new AtlasRegion(); + AtlasPage page = new AtlasPage(); + page.rendererObject = mat; + atlasRegion.page = page; + + //cache it + atlasTable[instanceId] = atlasRegion; + } + + Rect texRect = sprite.textureRect; + + //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; + + //TODO: make sure this rotation thing actually works + bool rotated = false; + if(sprite.packed) + rotated = sprite.packingRotation == SpritePackingRotation.Any; + + //do some math and assign UVs and sizes + attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated); + attachment.RendererObject = atlasRegion; + attachment.SetColor(Color.white); + attachment.ScaleX = 1; + attachment.ScaleY = 1; + attachment.RegionOffsetX = sprite.rect.width * (0.5f - Mathf.InverseLerp(bounds.min.x, bounds.max.x, 0)) / sprite.pixelsPerUnit; + attachment.RegionOffsetY = sprite.rect.height * (0.5f - Mathf.InverseLerp(bounds.min.y, bounds.max.y, 0)) / sprite.pixelsPerUnit; + attachment.Width = size.x; + attachment.Height = size.y; + attachment.RegionWidth = size.x; + attachment.RegionHeight = size.y; + attachment.RegionOriginalWidth = size.x; + attachment.RegionOriginalHeight = size.y; + attachment.UpdateOffset(); + + return attachment; + } + + public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { + //TODO: Unity 5 only + throw new System.NotImplementedException(); + } + + public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, string name, string path) { + throw new System.NotImplementedException(); + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { + throw new System.NotImplementedException(); + } +} \ No newline at end of file diff --git a/spine-unity/Assets/spine-unity/SpriteAttacher.cs.meta b/spine-unity/Assets/spine-unity/SpriteAttacher.cs.meta new file mode 100644 index 000000000..6f79b89c2 --- /dev/null +++ b/spine-unity/Assets/spine-unity/SpriteAttacher.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ee7b5e36685e2445a0097de42940987 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: From 18bbcfdc6a17bd3659e8b6af9d594f4790b17f6d Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 13 Mar 2015 20:15:29 -0700 Subject: [PATCH 2/3] Formatting clean up --- .../Assets/spine-unity/SkeletonExtensions.cs | 26 +++++++++---------- .../Assets/spine-unity/SpriteAttacher.cs | 8 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index e4d4a35fc..403497517 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -39,68 +39,68 @@ using Spine; public static class SkeletonExtensions { - public static void SetColor(this Slot slot, Color color) { + public static void SetColor (this Slot slot, Color color) { slot.A = color.a; slot.R = color.r; slot.G = color.g; slot.B = color.b; } - public static void SetColor(this Slot slot, Color32 color) { + public static void SetColor (this Slot slot, Color32 color) { slot.A = color.a / 255f; slot.R = color.r / 255f; slot.G = color.g / 255f; slot.B = color.b / 255f; } - public static void SetColor(this RegionAttachment attachment, Color color) { + public static void SetColor (this RegionAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor(this RegionAttachment attachment, Color32 color) { + public static void SetColor (this RegionAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetColor(this MeshAttachment attachment, Color color) { + public static void SetColor (this MeshAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor(this MeshAttachment attachment, Color32 color) { + public static void SetColor (this MeshAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetColor(this SkinnedMeshAttachment attachment, Color color) { + public static void SetColor (this SkinnedMeshAttachment attachment, Color color) { attachment.A = color.a; attachment.R = color.r; attachment.G = color.g; attachment.B = color.b; } - public static void SetColor(this SkinnedMeshAttachment attachment, Color32 color) { + public static void SetColor (this SkinnedMeshAttachment attachment, Color32 color) { attachment.A = color.a / 255f; attachment.R = color.r / 255f; attachment.G = color.g / 255f; attachment.B = color.b / 255f; } - public static void SetPosition(this Bone bone, Vector2 position) { + public static void SetPosition (this Bone bone, Vector2 position) { bone.X = position.x; bone.Y = position.y; } - public static void SetPosition(this Bone bone, Vector3 position) { + public static void SetPosition (this Bone bone, Vector3 position) { bone.X = position.x; bone.Y = position.y; } @@ -114,15 +114,15 @@ public static class SkeletonExtensions { loader = null; } - public static void AddUnitySprite(this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton"){ + public static void AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton") { var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); var att = loader.NewRegionAttachment(null, sprite.name, ""); var slotIndex = skeletonData.FindSlotIndex(slotName); Skin skin = skeletonData.defaultSkin; - if(skinName != "") + if (skinName != "") skin = skeletonData.FindSkin(skinName); - + skin.AddAttachment(slotIndex, att.Name, att); diff --git a/spine-unity/Assets/spine-unity/SpriteAttacher.cs b/spine-unity/Assets/spine-unity/SpriteAttacher.cs index 1c79423fc..927d4285a 100644 --- a/spine-unity/Assets/spine-unity/SpriteAttacher.cs +++ b/spine-unity/Assets/spine-unity/SpriteAttacher.cs @@ -25,11 +25,11 @@ public class SpriteAttacher : MonoBehaviour { public void Attach () { var skeletonRenderer = GetComponent(); - if(loader == null) + if (loader == null) //create loader instance, tell it what sprite and shader to use loader = new SpriteAttachmentLoader(sprite, Shader.Find("Spine/Skeleton")); - if(attachment == null) + if (attachment == null) attachment = loader.NewRegionAttachment(null, sprite.name, ""); skeletonRenderer.skeleton.FindSlot(slot).Attachment = attachment; @@ -102,7 +102,7 @@ public class SpriteAttachmentLoader : AttachmentLoader { } else { //Setup new material Material mat = new Material(shader); - if(sprite.packed) + if (sprite.packed) mat.name = "Unity Packed Sprite Material"; else mat.name = sprite.name + " Sprite Material"; @@ -131,7 +131,7 @@ public class SpriteAttachmentLoader : AttachmentLoader { //TODO: make sure this rotation thing actually works bool rotated = false; - if(sprite.packed) + if (sprite.packed) rotated = sprite.packingRotation == SpritePackingRotation.Any; //do some math and assign UVs and sizes From fcf90be386624775941c759dce2b28a842789c8e Mon Sep 17 00:00:00 2001 From: Fenrisul Date: Fri, 13 Mar 2015 20:24:30 -0700 Subject: [PATCH 3/3] Return Attachment after adding from Sprite. Misc clean up --- .../Assets/spine-unity/SkeletonExtensions.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs index 403497517..e073bcca4 100644 --- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs @@ -105,28 +105,24 @@ public static class SkeletonExtensions { bone.Y = position.y; } - public static void AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton") { - var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); - - var att = loader.NewRegionAttachment(null, sprite.name, ""); + public static Attachment AttachUnitySprite (this Skeleton skeleton, string slotName, Sprite sprite, string shaderName = "Spine/Skeleton") { + var att = sprite.ToRegionAttachment(shaderName); skeleton.FindSlot(slotName).Attachment = att; - loader = null; + return att; } - public static void AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton") { - var loader = new SpriteAttachmentLoader(sprite, Shader.Find(shaderName)); - var att = loader.NewRegionAttachment(null, sprite.name, ""); + public static Attachment AddUnitySprite (this SkeletonData skeletonData, string slotName, Sprite sprite, string skinName = "", string shaderName = "Spine/Skeleton") { + var att = sprite.ToRegionAttachment(shaderName); var slotIndex = skeletonData.FindSlotIndex(slotName); Skin skin = skeletonData.defaultSkin; if (skinName != "") skin = skeletonData.FindSkin(skinName); - skin.AddAttachment(slotIndex, att.Name, att); - loader = null; + return att; } public static RegionAttachment ToRegionAttachment (this Sprite sprite, string shaderName = "Spine/Skeleton") { @@ -135,5 +131,4 @@ public static class SkeletonExtensions { loader = null; return att; } - } \ No newline at end of file