SpriteAttacher.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Spine;
  5. public class SpriteAttacher : MonoBehaviour
  6. {
  7. public bool attachOnStart = true;
  8. public bool keepLoaderInMemory = true;
  9. public Sprite sprite;
  10. [SpineSlot]
  11. public string slot;
  12. private SpriteAttachmentLoader loader;
  13. private RegionAttachment attachment;
  14. void Start()
  15. {
  16. if (attachOnStart)
  17. Attach();
  18. }
  19. public void Attach()
  20. {
  21. var skeletonRenderer = GetComponent<SkeletonRenderer>();
  22. if (loader == null)
  23. //create loader instance, tell it what sprite and shader to use
  24. loader = new SpriteAttachmentLoader(sprite, Shader.Find("Spine/Skeleton"));
  25. if (attachment == null)
  26. attachment = loader.NewRegionAttachment(null, sprite.name, "");
  27. skeletonRenderer.skeleton.FindSlot(slot).Attachment = attachment;
  28. if (!keepLoaderInMemory)
  29. loader = null;
  30. }
  31. }
  32. public class SpriteAttachmentLoader : AttachmentLoader
  33. {
  34. //TODO: Memory cleanup functions
  35. //IMPORTANT: Make sure you clear this when you don't need it anymore. Goodluck.
  36. public static Dictionary<int, AtlasRegion> atlasTable = new Dictionary<int, AtlasRegion>();
  37. //Shouldn't need to clear this, should just prevent redoing premultiply alpha pass on packed atlases
  38. public static List<int> premultipliedAtlasIds = new List<int>();
  39. Sprite sprite;
  40. Shader shader;
  41. public SpriteAttachmentLoader(Sprite sprite, Shader shader)
  42. {
  43. if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight)
  44. {
  45. Debug.LogError("Tight Packer Policy not supported yet!");
  46. return;
  47. }
  48. this.sprite = sprite;
  49. this.shader = shader;
  50. Texture2D tex = sprite.texture;
  51. //premultiply texture if it hasn't been yet
  52. int instanceId = tex.GetInstanceID();
  53. if (!premultipliedAtlasIds.Contains(instanceId))
  54. {
  55. try
  56. {
  57. var colors = tex.GetPixels();
  58. Color c;
  59. float a;
  60. for (int i = 0; i < colors.Length; i++)
  61. {
  62. c = colors[i];
  63. a = c.a;
  64. c.r *= a;
  65. c.g *= a;
  66. c.b *= a;
  67. colors[i] = c;
  68. }
  69. tex.SetPixels(colors);
  70. tex.Apply();
  71. premultipliedAtlasIds.Add(instanceId);
  72. }
  73. catch
  74. {
  75. //texture is not readable! Can't pre-multiply it, you're on your own.
  76. }
  77. }
  78. }
  79. public RegionAttachment NewRegionAttachment(Skin skin, string name, string path)
  80. {
  81. RegionAttachment attachment = new RegionAttachment(name);
  82. Texture2D tex = sprite.texture;
  83. int instanceId = tex.GetInstanceID();
  84. AtlasRegion atlasRegion;
  85. //check cache first
  86. if (atlasTable.ContainsKey(instanceId))
  87. {
  88. atlasRegion = atlasTable[instanceId];
  89. }
  90. else
  91. {
  92. //Setup new material
  93. Material mat = new Material(shader);
  94. if (sprite.packed)
  95. mat.name = "Unity Packed Sprite Material";
  96. else
  97. mat.name = sprite.name + " Sprite Material";
  98. mat.mainTexture = tex;
  99. //create faux-region to play nice with SkeletonRenderer
  100. atlasRegion = new AtlasRegion();
  101. AtlasPage page = new AtlasPage();
  102. page.rendererObject = mat;
  103. atlasRegion.page = page;
  104. //cache it
  105. atlasTable[instanceId] = atlasRegion;
  106. }
  107. Rect texRect = sprite.textureRect;
  108. //normalize rect to UV space of packed atlas
  109. texRect.x = Mathf.InverseLerp(0, tex.width, texRect.x);
  110. texRect.y = Mathf.InverseLerp(0, tex.height, texRect.y);
  111. texRect.width = Mathf.InverseLerp(0, tex.width, texRect.width);
  112. texRect.height = Mathf.InverseLerp(0, tex.height, texRect.height);
  113. Bounds bounds = sprite.bounds;
  114. Vector3 size = bounds.size;
  115. //TODO: make sure this rotation thing actually works
  116. bool rotated = false;
  117. if (sprite.packed)
  118. rotated = sprite.packingRotation == SpritePackingRotation.Any;
  119. //do some math and assign UVs and sizes
  120. attachment.SetUVs(texRect.xMin, texRect.yMax, texRect.xMax, texRect.yMin, rotated);
  121. attachment.RendererObject = atlasRegion;
  122. attachment.SetColor(Color.white);
  123. attachment.ScaleX = 1;
  124. attachment.ScaleY = 1;
  125. attachment.RegionOffsetX = sprite.rect.width * (0.5f - Mathf.InverseLerp(bounds.min.x, bounds.max.x, 0)) / sprite.pixelsPerUnit;
  126. attachment.RegionOffsetY = sprite.rect.height * (0.5f - Mathf.InverseLerp(bounds.min.y, bounds.max.y, 0)) / sprite.pixelsPerUnit;
  127. attachment.Width = size.x;
  128. attachment.Height = size.y;
  129. attachment.RegionWidth = size.x;
  130. attachment.RegionHeight = size.y;
  131. attachment.RegionOriginalWidth = size.x;
  132. attachment.RegionOriginalHeight = size.y;
  133. attachment.UpdateOffset();
  134. return attachment;
  135. }
  136. public MeshAttachment NewMeshAttachment(Skin skin, string name, string path)
  137. {
  138. //TODO: Unity 5 only
  139. throw new System.NotImplementedException();
  140. }
  141. public SkinnedMeshAttachment NewSkinnedMeshAttachment(Skin skin, string name, string path)
  142. {
  143. throw new System.NotImplementedException();
  144. }
  145. public BoundingBoxAttachment NewBoundingBoxAttachment(Skin skin, string name)
  146. {
  147. throw new System.NotImplementedException();
  148. }
  149. }