Jelajahi Sumber

SpriteAttachmentLoader and friends

Fenrisul 10 tahun lalu
induk
melakukan
f73d6e5d1c

+ 31 - 0
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;
+	}
+
 }

+ 168 - 0
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<SkeletonRenderer>();
+
+		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<int, AtlasRegion> atlasTable = new Dictionary<int, AtlasRegion>();
+
+	//Shouldn't need to clear this, should just prevent redoing premultiply alpha pass on packed atlases
+	public static List<int> premultipliedAtlasIds = new List<int>();
+
+	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();
+	}
+}

+ 8 - 0
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: