Inheritance: AttachmentLoader
		void Apply (SkeletonRenderer skeletonRenderer) {
			atlas = atlasAsset.GetAtlas();

			AtlasAttachmentLoader loader = new AtlasAttachmentLoader(atlas);

			float scaleMultiplier = skeletonRenderer.skeletonDataAsset.scale;

			var enumerator = attachments.GetEnumerator();
			while (enumerator.MoveNext()) {
				var entry = (SlotRegionPair)enumerator.Current;
				var regionAttachment = loader.NewRegionAttachment(null, entry.region, entry.region);
				regionAttachment.Width = regionAttachment.RegionOriginalWidth * scaleMultiplier;
				regionAttachment.Height = regionAttachment.RegionOriginalHeight * scaleMultiplier;

				regionAttachment.SetColor(new Color(1, 1, 1, 1));
				regionAttachment.UpdateOffset();

				var slot = skeletonRenderer.skeleton.FindSlot(entry.slot);
				slot.Attachment = regionAttachment;
			}
		}
    public SkeletonData GetSkeletonData(bool quiet)
    {
        if (atlasAssets == null) {
            atlasAssets = new AtlasAsset[0];
            if (!quiet)
                Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
            Reset();
            return null;
        }

        if (skeletonJSON == null) {
            if (!quiet)
                Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this);
            Reset();
            return null;
        }

        #if !SPINE_TK2D
        if (atlasAssets.Length == 0) {
            Reset();
            return null;
        }
        #else
        if (atlasAssets.Length == 0 && spriteCollection == null) {
            Reset();
            return null;
        }
        #endif

        Atlas[] atlasArr = new Atlas[atlasAssets.Length];
        for (int i = 0; i < atlasAssets.Length; i++) {
            if (atlasAssets[i] == null) {
                Reset();
                return null;
            }
            atlasArr[i] = atlasAssets[i].GetAtlas();
            if (atlasArr[i] == null) {
                Reset();
                return null;
            }
        }

        if (skeletonData != null)
            return skeletonData;

        AttachmentLoader attachmentLoader;
        float skeletonDataScale;

        #if !SPINE_TK2D
        attachmentLoader = new AtlasAttachmentLoader(atlasArr);
        skeletonDataScale = scale;
        #else
        if (spriteCollection != null) {
            attachmentLoader = new SpriteCollectionAttachmentLoader(spriteCollection);
            skeletonDataScale = (1.0f / (spriteCollection.invOrthoSize * spriteCollection.halfTargetHeight) * scale);
        } else {
            if (atlasArr.Length == 0) {
                Reset();
                if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
                return null;
            }
            attachmentLoader = new AtlasAttachmentLoader(atlasArr);
            skeletonDataScale = scale;
        }
        #endif

        try {
            //var stopwatch = new System.Diagnostics.Stopwatch();
            if (skeletonJSON.name.ToLower().Contains(".skel")) {
                var input = new MemoryStream(skeletonJSON.bytes);
                var binary = new SkeletonBinary(attachmentLoader);
                binary.Scale = skeletonDataScale;
                //stopwatch.Start();
                skeletonData = binary.ReadSkeletonData(input);
            } else {
                var input = new StringReader(skeletonJSON.text);
                var json = new SkeletonJson(attachmentLoader);
                json.Scale = skeletonDataScale;
                //stopwatch.Start();
                skeletonData = json.ReadSkeletonData(input);
            }
            //stopwatch.Stop();
            //Debug.Log(stopwatch.Elapsed);
        } catch (Exception ex) {
            if (!quiet)
                Debug.LogError("Error reading skeleton JSON file for SkeletonData asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this);
            return null;
        }

        stateData = new AnimationStateData(skeletonData);
        FillStateData();

        return skeletonData;
    }
		public SkeletonData GetSkeletonData (bool quiet) {
			if (atlasAssets == null) {
				atlasAssets = new AtlasAsset[0];
				if (!quiet)
					Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
				Clear();
				return null;
			}

			if (skeletonJSON == null) {
				if (!quiet)
					Debug.LogError("Skeleton JSON file not set for SkeletonData asset: " + name, this);
				Clear();
				return null;
			}

			#if !SPINE_TK2D
			if (atlasAssets.Length == 0) {
				Clear();
				return null;
			}
			#else
			if (atlasAssets.Length == 0 && spriteCollection == null) {
				Clear();
				return null;
			}
			#endif
			if (skeletonData != null)
				return skeletonData;

			AttachmentLoader attachmentLoader;
			float skeletonDataScale;
			Atlas[] atlasArray = this.GetAtlasArray();

			#if !SPINE_TK2D
			attachmentLoader = new AtlasAttachmentLoader(atlasArray);
			skeletonDataScale = scale;
			#else
			if (spriteCollection != null) {
				attachmentLoader = new Spine.Unity.TK2D.SpriteCollectionAttachmentLoader(spriteCollection);
				skeletonDataScale = (1.0f / (spriteCollection.invOrthoSize * spriteCollection.halfTargetHeight) * scale);
			} else {
				if (atlasArray.Length == 0) {
					Reset();
					if (!quiet) Debug.LogError("Atlas not set for SkeletonData asset: " + name, this);
					return null;
				}
				attachmentLoader = new AtlasAttachmentLoader(atlasArray);
				skeletonDataScale = scale;
			}
			#endif

			bool isBinary = skeletonJSON.name.ToLower().Contains(".skel");
			SkeletonData loadedSkeletonData;

			try {
				if (isBinary)
					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.bytes, attachmentLoader, skeletonDataScale);
				else
					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.text, attachmentLoader, skeletonDataScale);

			} catch (Exception ex) {
				if (!quiet)
					Debug.LogError("Error reading skeleton JSON file for SkeletonData asset: " + name + "\n" + ex.Message + "\n" + ex.StackTrace, this);
				return null;

			}

			this.InitializeWithData(loadedSkeletonData);

			return skeletonData;
		}