Exemple #1
0
    void OnDisable()
    {
        ClearTextureCache();

        _spriteCollection = null;
        tk2dEditorUtility.CollectAndUnloadUnusedAssets();
    }
 public void SetGenerator(tk2dSpriteCollection spriteCollection)
 {
     this._spriteCollection = spriteCollection;
     this.firstRun          = true;
     spriteCollectionProxy  = new SpriteCollectionProxy(spriteCollection);
     PopulateEntries();
 }
    public static void CreateSpriteCollectionModified()
    {
        string path = tk2dEditorUtility.CreateNewPrefab("SpriteCollection");

        if (path.Length != 0)
        {
            GameObject           go = new GameObject();
            tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>();
            spriteCollection.filterMode = FilterMode.Bilinear;
            spriteCollection.sizeDef    = tk2dSpriteCollectionSize.PixelsPerMeter(40);
            spriteCollection.version    = tk2dSpriteCollection.CURRENT_VERSION;
            if (tk2dCamera.Editor__Inst != null)
            {
                spriteCollection.sizeDef.CopyFrom(tk2dSpriteCollectionSize.ForTk2dCamera(tk2dCamera.Editor__Inst));
            }
            tk2dEditorUtility.SetGameObjectActive(go, false);

            Object p = PrefabUtility.CreateEmptyPrefab(path);
            PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab);

            GameObject.DestroyImmediate(go);

            // Select object
            Selection.activeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object));
        }
    }
    public override void OnInspectorGUI()
    {
        tk2dSpriteCollection gen = (tk2dSpriteCollection)target;

        GUILayout.BeginVertical();
        GUILayout.Space(8);

        if (gen.managedSpriteCollection)
        {
            string label         = showDefaultInspector?"Hide Default Inspector":"Show Default Inspector";
            int    buttonPressed = tk2dGuiUtility.InfoBoxWithButtons("This is a managed sprite collection. Please do not modify.",
                                                                     tk2dGuiUtility.WarningLevel.Info,
                                                                     new string[] { label });
            if (buttonPressed == 0)
            {
                showDefaultInspector = !showDefaultInspector;
            }
            if (showDefaultInspector)
            {
                GUILayout.Space(16);
                DrawDefaultInspector();
            }
        }
        else
        {
            string assetPath   = AssetDatabase.GetAssetPath(gen).ToLower();
            bool   inResources = assetPath.IndexOf("/resources/") != -1;

            if (inResources)
            {
                string msg = "Sprite collection is in a resources directory. " +
                             "All source textures will be included in build.\n\n" +
                             "Editor is disabled. Move it out of the resources directory to continue.";
                tk2dGuiUtility.InfoBox(msg, tk2dGuiUtility.WarningLevel.Error);
            }
            else
            {
                GUILayout.BeginHorizontal();
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("Open Editor...", GUILayout.MinWidth(120)))
                {
                    if (gen.name == defaultSpriteCollectionName)
                    {
                        EditorUtility.DisplayDialog("Invalid Sprite Collection name", "Please rename sprite collection before proceeding", "Ok");
                    }
                    else
                    {
                        tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "SpriteCollection") as tk2dSpriteCollectionEditorPopup;
                        v.SetGenerator(gen);
                    }
                }
                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
            }
        }

        EditorGUILayout.EndVertical();

        GUILayout.Space(64);
    }
    static void DoCollectionCreate()
    {
        string path = tk2dEditorUtility.CreateNewPrefab(defaultSpriteCollectionName);

        if (path.Length != 0)
        {
            GameObject           go = new GameObject();
            tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>();
            spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION;
            if (tk2dCamera.Editor__Inst != null)
            {
                spriteCollection.sizeDef.CopyFrom(tk2dSpriteCollectionSize.ForTk2dCamera(tk2dCamera.Editor__Inst));
            }
            tk2dEditorUtility.SetGameObjectActive(go, false);

#if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4)
            Object p = EditorUtility.CreateEmptyPrefab(path);
            EditorUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab);
#else
            Object p = PrefabUtility.CreateEmptyPrefab(path);
            PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab);
#endif

            GameObject.DestroyImmediate(go);

            // Select object
            Selection.activeObject = AssetDatabase.LoadAssetAtPath(path, typeof(UnityEngine.Object));
        }
    }
Exemple #6
0
        public override void DoLocalize(Localize cmp, string mainTranslation, string secondaryTranslation)
        {
            if (string.IsNullOrEmpty(mainTranslation))
            {
                return;
            }

            //--[ Localize Atlas ]----------
            tk2dSpriteCollection newCollection = cmp.GetSecondaryTranslatedObj <tk2dSpriteCollection>(ref mainTranslation, ref secondaryTranslation);

            if (newCollection != null)
            {
                if (mTarget.CurrentSprite.name != mainTranslation || mTarget.Collection.name != secondaryTranslation)
                {
                    mTarget.SetSprite(newCollection.spriteCollection, mainTranslation);
                }
            }
            else
            {
                if (mTarget.CurrentSprite.name != mainTranslation)
                {
                    mTarget.SetSprite(mainTranslation);
                }
            }
        }
        public static void Build(tk2dSpriteCollection data)
        {
            if (data.linkedSpriteCollections.Count > 0 && !data.disableTrimming)
            {
                return;
            }

            string errors     = "";
            int    errorCount = 0;
            string root       = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)) + "/Linked";

            foreach (tk2dLinkedSpriteCollection link in data.linkedSpriteCollections)
            {
                if (link.spriteCollection == null)
                {
                    if (!System.IO.Directory.Exists(root))
                    {
                        System.IO.Directory.CreateDirectory(root);
                    }
                    link.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, data.name + link.name);
                }

                tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy proxy = new tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy(data, false);
                proxy.CopyBuiltFromSource(link.spriteCollection);
                proxy.linkedSpriteCollections.Clear();                 // stop recursion
                string thisErrors = "";

                foreach (tk2dSpriteCollectionDefinition tp in proxy.textureParams)
                {
                    if (tp.texture != null)
                    {
                        Texture2D repl = FindReplacementTexture(tp.texture, link.name);
                        if (repl == null)
                        {
                            thisErrors += string.Format("Unable to find replacement for texture '{0}' for link '{1}'\n", tp.texture.name, link.name);
                            ++errorCount;
                        }
                        tp.texture = repl;
                    }
                }

                if (thisErrors.Length == 0)
                {
                    proxy.CopyToTarget(link.spriteCollection);
                    link.spriteCollection.linkParent = data;
                    EditorUtility.SetDirty(link.spriteCollection);

                    tk2dSpriteCollectionBuilder.Rebuild(link.spriteCollection);
                }
                else
                {
                    errors += thisErrors;
                }
            }

            if (errors.Length > 0)
            {
                Debug.LogError("There were " + errorCount.ToString() + " errors building the sprite collection\n" + errors);
            }
        }
Exemple #8
0
    public static void SpriteSelector(tk2dSpriteCollectionData spriteCollection, int spriteId, SpriteChangedCallback callback, object callbackData)
    {
        tk2dSpriteCollectionData newCollection = spriteCollection;
        int newSpriteId = spriteId;

        GUILayout.BeginHorizontal();

        GUILayout.BeginVertical();

        GUILayout.BeginHorizontal();
        newCollection = SpriteCollectionList("Collection", spriteCollection);
        if (tk2dPreferences.inst.displayEditSpriteButton &&
            GUILayout.Button("o", EditorStyles.miniButton, GUILayout.Width(18)))
        {
            EditorGUIUtility.PingObject(spriteCollection);
        }
        GUILayout.EndHorizontal();

        if (spriteCollection != null && spriteCollection.Count != 0)
        {
            if (spriteId < 0 || spriteId >= spriteCollection.Count || !spriteCollection.inst.spriteDefinitions[spriteId].Valid)
            {
                newSpriteId = spriteCollection.FirstValidDefinitionIndex;
            }

            GUILayout.BeginHorizontal();
            newSpriteId = SpriteList("Sprite", newSpriteId, spriteCollection);

            if (tk2dPreferences.inst.displayEditSpriteButton &&
                spriteCollection != null && spriteCollection.dataGuid != TransientGUID &&
                GUILayout.Button("e", EditorStyles.miniButton, GUILayout.Width(18), GUILayout.MaxHeight(14f)))
            {
                tk2dSpriteCollection gen = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(spriteCollection.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;
                if (gen != null)
                {
                    tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup;
                    v.SetGeneratorAndSelectedSprite(gen, spriteId);
                }
            }

            GUILayout.EndHorizontal();
        }

        if (callback != null && (newCollection != spriteCollection || newSpriteId != spriteId))
        {
            callback(newCollection, newSpriteId, callbackData);
        }
        GUILayout.EndVertical();

        if (GUILayout.Button("...", GUILayout.Height(32), GUILayout.Width(32)))
        {
            SpriteSelectorPopup(spriteCollection, spriteId, callback, callbackData);
        }

        GUILayout.EndHorizontal();
    }
		public static void ValidateTextureParam(tk2dSpriteCollection gen, int i) {
			var param = gen.textureParams[i];
			if (param.texture != null && gen.linkParent != null) {
				if (gen.linkParent.textureParams[i].texture == null ||
					gen.linkParent.textureParams[i].texture.width != param.texture.width ||
					gen.linkParent.textureParams[i].texture.height != param.texture.height) {
					Debug.LogError("Linked sprite collection mismatch " + param.texture.name);
				}
			}			
		}
Exemple #10
0
 public void SelectBody3()
 {
     playerCollection = null;
     playerCollection = database.GetCollectionByName("皮肤3");
     //playerCollection = Resources.Load("Collections/人物3图集", typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;
     if (playerCollection == null)
     {
         Debug.LogWarning("加载图集失败!");
     }
 }
		public static void ValidateLinkedSpriteCollection(tk2dSpriteCollection gen) {
			if (gen.linkParent == null) {
				return;
			}

			if (gen.textureParams.Length != gen.linkParent.textureParams.Length) {
				Debug.LogError("Linked sprite collection mismatch. Please rebuild source collection");
				gen.linkParent = null;
			}
		}
        public void CopyBuiltFromSource(tk2dSpriteCollection source)
        {
            SpriteCollectionProxy target = this;

            target.spriteCollection = source.spriteCollection;
            CopyArray(ref target.altMaterials, source.altMaterials);
            CopyArray(ref target.atlasMaterials, source.atlasMaterials);
            CopyArray(ref target.atlasTextures, source.atlasTextures);
            CopyArray(ref target.atlasTextureFiles, source.atlasTextureFiles);
        }
Exemple #13
0
 public void SelectWeapon2()
 {
     weaponCollection = null;
     weaponCollection = database.GetCollectionByName("武器2");
     //weaponCollection = Resources.Load("Collections/武器2图集", typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;
     if (weaponCollection == null)
     {
         Debug.LogWarning("加载图集失败!");
     }
 }
	override public void OnInspectorGUI () {
		serializedObject.Update();
		SkeletonDataAsset asset = (SkeletonDataAsset)target;

		tk2dSpriteCollection sprites = EditorGUILayout.ObjectField("Sprite Collection", asset.spriteCollection, typeof(tk2dSpriteCollection), false) as tk2dSpriteCollection;
		if (sprites != null)
			spriteCollection.objectReferenceValue = sprites.spriteCollection;

		EditorGUILayout.PropertyField(skeletonJSON);
		EditorGUILayout.PropertyField(scale);
		
		SkeletonData skeletonData = asset.GetSkeletonData(asset.spriteCollection == null || asset.skeletonJSON == null);
		if (skeletonData != null) {
			showAnimationStateData = EditorGUILayout.Foldout(showAnimationStateData, "Animation State Data");
			if (showAnimationStateData) {
				// Animation names.
				String[] animations = new String[skeletonData.Animations.Count];
				for (int i = 0; i < animations.Length; i++)
					animations[i] = skeletonData.Animations[i].Name;
			
				for (int i = 0; i < fromAnimation.arraySize; i++) {
					SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
					SerializedProperty to = toAnimation.GetArrayElementAtIndex(i);
					SerializedProperty durationProp = duration.GetArrayElementAtIndex(i);
					EditorGUILayout.BeginHorizontal();
					from.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, from.stringValue), 0), animations)];
					to.stringValue = animations[EditorGUILayout.Popup(Math.Max(Array.IndexOf(animations, to.stringValue), 0), animations)];
					durationProp.floatValue = EditorGUILayout.FloatField(durationProp.floatValue);
					if (GUILayout.Button("Delete")) {
						duration.DeleteArrayElementAtIndex(i);
						toAnimation.DeleteArrayElementAtIndex(i);
						fromAnimation.DeleteArrayElementAtIndex(i);
					}
					EditorGUILayout.EndHorizontal();
				}
				EditorGUILayout.BeginHorizontal();
				EditorGUILayout.Space();
				if (GUILayout.Button("Add Mix")) {
					duration.arraySize++;
					toAnimation.arraySize++;
					fromAnimation.arraySize++;
				}
				EditorGUILayout.Space();
				EditorGUILayout.EndHorizontal();
			}
		}
		
		if (!Application.isPlaying) {
			if (serializedObject.ApplyModifiedProperties() ||
				(UnityEngine.Event.current.type == EventType.ValidateCommand && UnityEngine.Event.current.commandName == "UndoRedoPerformed")
			) {
				asset.Clear();
			}
		}
	}
Exemple #15
0
        public void CopyToTarget(tk2dSpriteCollection target)
        {
            target.textureParams = textureParams.ToArray();
            target.spriteSheets  = spriteSheets.ToArray();
            target.fonts         = fonts.ToArray();

            var source = this;

            target.platforms = new List <tk2dSpriteCollectionPlatform>();
            foreach (tk2dSpriteCollectionPlatform plat in source.platforms)
            {
                tk2dSpriteCollectionPlatform p = new tk2dSpriteCollectionPlatform();
                p.CopyFrom(plat);
                target.platforms.Add(p);
            }
            target.assetName = source.assetName;
            target.loadable  = source.loadable;

            target.maxTextureSize      = source.maxTextureSize;
            target.forceTextureSize    = source.forceTextureSize;
            target.forcedTextureWidth  = source.forcedTextureWidth;
            target.forcedTextureHeight = source.forcedTextureHeight;

            target.textureCompression   = source.textureCompression;
            target.atlasWidth           = source.atlasWidth;
            target.atlasHeight          = source.atlasHeight;
            target.forceSquareAtlas     = source.forceSquareAtlas;
            target.atlasWastage         = source.atlasWastage;
            target.allowMultipleAtlases = source.allowMultipleAtlases;

            target.spriteCollection   = source.spriteCollection;
            target.premultipliedAlpha = source.premultipliedAlpha;

            CopyArray(ref target.altMaterials, source.altMaterials);
            CopyArray(ref target.atlasMaterials, source.atlasMaterials);
            CopyArray(ref target.atlasTextures, source.atlasTextures);

            target.useTk2dCamera        = source.useTk2dCamera;
            target.targetHeight         = source.targetHeight;
            target.targetOrthoSize      = source.targetOrthoSize;
            target.globalScale          = source.globalScale;
            target.physicsDepth         = source.physicsDepth;
            target.disableTrimming      = source.disableTrimming;
            target.normalGenerationMode = source.normalGenerationMode;
            target.padAmount            = source.padAmount;
            target.autoUpdate           = source.autoUpdate;
            target.editorDisplayScale   = source.editorDisplayScale;

            // Texture settings
            target.filterMode = source.filterMode;
            target.wrapMode   = source.wrapMode;
            target.userDefinedTextureSettings = source.userDefinedTextureSettings;
            target.mipmapEnabled = source.mipmapEnabled;
            target.anisoLevel    = source.anisoLevel;
        }
        public static bool CheckAndFixUpParams(tk2dSpriteCollection gen)
        {
            if (gen.DoNotUse__TextureRefs != null && gen.textureParams != null && gen.DoNotUse__TextureRefs.Length != gen.textureParams.Length)
            {
                tk2dSpriteCollectionDefinition[] newDefs = new tk2dSpriteCollectionDefinition[gen.DoNotUse__TextureRefs.Length];
                int c = Mathf.Min(newDefs.Length, gen.textureParams.Length);

                if (gen.DoNotUse__TextureRefs.Length > gen.textureParams.Length)
                {
                    Texture2D[] newTexRefs = new Texture2D[gen.DoNotUse__TextureRefs.Length - gen.textureParams.Length];
                    System.Array.Copy(gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs, 0, newTexRefs.Length);
                    System.Array.Sort(newTexRefs, (Texture2D a, Texture2D b) => tk2dSpriteGuiUtility.NameCompare(a?a.name:"", b?b.name:""));
                    System.Array.Copy(newTexRefs, 0, gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs.Length);
                }

                for (int i = 0; i < c; ++i)
                {
                    newDefs[i] = new tk2dSpriteCollectionDefinition();
                    newDefs[i].CopyFrom(gen.textureParams[i]);
                }
                for (int i = c; i < newDefs.Length; ++i)
                {
                    newDefs[i]              = new tk2dSpriteCollectionDefinition();
                    newDefs[i].pad          = gen.defaults.pad;
                    newDefs[i].additive     = gen.defaults.additive;
                    newDefs[i].anchor       = gen.defaults.anchor;
                    newDefs[i].scale        = gen.defaults.scale;
                    newDefs[i].colliderType = gen.defaults.colliderType;
                }
                gen.textureParams = newDefs;
            }

            // clear thumbnails on build
            foreach (var param in gen.textureParams)
            {
                param.thumbnailTexture = null;
            }

            foreach (var param in gen.textureParams)
            {
                if (gen.allowMultipleAtlases && param.dice)
                {
                    EditorUtility.DisplayDialog("Error",
                                                "Multiple atlas spanning is not allowed when there are textures with dicing enabled in the SpriteCollection.",
                                                "Ok");

                    gen.allowMultipleAtlases = false;

                    return(false);
                }
            }

            return(true);
        }
		public static bool CheckAndFixUpParams(tk2dSpriteCollection gen)
		{
			if (gen.DoNotUse__TextureRefs != null && gen.textureParams != null && gen.DoNotUse__TextureRefs.Length != gen.textureParams.Length)
	        {
				tk2dSpriteCollectionDefinition[] newDefs = new tk2dSpriteCollectionDefinition[gen.DoNotUse__TextureRefs.Length];
				int c = Mathf.Min( newDefs.Length, gen.textureParams.Length );

				if (gen.DoNotUse__TextureRefs.Length > gen.textureParams.Length)
				{
					Texture2D[] newTexRefs = new Texture2D[gen.DoNotUse__TextureRefs.Length - gen.textureParams.Length];
					System.Array.Copy(gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs, 0, newTexRefs.Length);
					System.Array.Sort(newTexRefs, (Texture2D a, Texture2D b) => tk2dSpriteGuiUtility.NameCompare(a?a.name:"", b?b.name:""));
					System.Array.Copy(newTexRefs, 0, gen.DoNotUse__TextureRefs, gen.textureParams.Length, newTexRefs.Length);
				}

				for (int i = 0; i < c; ++i)
				{
					newDefs[i] = new tk2dSpriteCollectionDefinition();
					newDefs[i].CopyFrom( gen.textureParams[i] );
				}
				for (int i = c; i < newDefs.Length; ++i)
				{
					newDefs[i] = new tk2dSpriteCollectionDefinition();
					newDefs[i].pad = gen.defaults.pad;
					newDefs[i].additive = gen.defaults.additive;
					newDefs[i].anchor = gen.defaults.anchor;
					newDefs[i].scale = gen.defaults.scale;
					newDefs[i].colliderType = gen.defaults.colliderType;
				}
				gen.textureParams = newDefs;
	        }

			// clear thumbnails on build
			foreach (var param in gen.textureParams)
			{
				param.thumbnailTexture = null;
			}

			foreach (var param in gen.textureParams)
			{
				if (gen.allowMultipleAtlases && param.dice)
				{
					EditorUtility.DisplayDialog("Error",
					                            "Multiple atlas spanning is not allowed when there are textures with dicing enabled in the SpriteCollection.",
								                "Ok");

					gen.allowMultipleAtlases = false;

					return false;
				}
			}

			return true;
		}
    static void SetUpSourceTextureFormats(tk2dSpriteCollection gen)
    {
        // make sure all textures are in the right format
        int numTexturesReimported          = 0;
        List <Texture2D> texturesToProcess = new List <Texture2D>();

        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            if (gen.textureRefs[i] != null)
            {
                texturesToProcess.Add(gen.textureRefs[i]);
            }
        }
        if (gen.spriteSheets != null)
        {
            for (int i = 0; i < gen.spriteSheets.Length; ++i)
            {
                if (gen.spriteSheets[i].texture != null)
                {
                    texturesToProcess.Add(gen.spriteSheets[i].texture);
                }
            }
        }
        foreach (var tex in texturesToProcess)
        {
            // make sure the source texture is npot and readable, and uncompressed
            string          thisTextPath = AssetDatabase.GetAssetPath(tex);
            TextureImporter importer     = (TextureImporter)TextureImporter.GetAtPath(thisTextPath);
            if (importer.textureType != TextureImporterType.Advanced ||
                importer.textureFormat != TextureImporterFormat.AutomaticTruecolor ||
                importer.npotScale != TextureImporterNPOTScale.None ||
                importer.isReadable != true ||
                importer.maxTextureSize < 4096)
            {
                importer.textureFormat  = TextureImporterFormat.AutomaticTruecolor;
                importer.textureType    = TextureImporterType.Advanced;
                importer.npotScale      = TextureImporterNPOTScale.None;
                importer.isReadable     = true;
                importer.mipmapEnabled  = false;
                importer.maxTextureSize = 4096;

                AssetDatabase.ImportAsset(thisTextPath);

                numTexturesReimported++;
            }
        }
        if (numTexturesReimported > 0)
        {
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
		public static void TrimTextureList(tk2dSpriteCollection gen)
		{
			// trim textureRefs & textureParams
			int lastNonEmpty = -1;
			for (int i = 0; i < gen.DoNotUse__TextureRefs.Length; ++i)
			{
				if (gen.DoNotUse__TextureRefs[i] != null) lastNonEmpty = i;
			}
			Texture2D[] textureRefs = gen.DoNotUse__TextureRefs;
			System.Array.Resize(ref textureRefs, lastNonEmpty + 1);
			System.Array.Resize(ref gen.textureParams, lastNonEmpty + 1);
			gen.DoNotUse__TextureRefs = textureRefs;
		}
        public static void ValidateLinkedSpriteCollection(tk2dSpriteCollection gen)
        {
            if (gen.linkParent == null)
            {
                return;
            }

            if (gen.textureParams.Length != gen.linkParent.textureParams.Length)
            {
                Debug.LogError("Linked sprite collection mismatch. Please rebuild source collection");
                gen.linkParent = null;
            }
        }
 public static string GetOrCreateDataPath(tk2dSpriteCollection gen)
 {
     if (gen.spriteCollection != null)
     {
         return System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(gen.spriteCollection));
     }
     else
     {
         string path = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(gen)) + "/" + gen.name + " Data";
         if (!System.IO.Directory.Exists(path))
             System.IO.Directory.CreateDirectory(path);
         return path;
     }
 }
 public static void InitializeSpriteCollectionPlatforms(tk2dSpriteCollection gen, string root)
 {
     // Create all missing platform directories and sprite collection objects
     for (int i = 0; i < gen.platforms.Count; ++i)
     {
         tk2dSpriteCollectionPlatform plat = gen.platforms[i];
         if (plat.name.Length > 0 && !plat.spriteCollection)
         {
             plat.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, gen.name + "@" + plat.name);
             plat.spriteCollection.managedSpriteCollection = true;
             EditorUtility.SetDirty(gen.spriteCollection);
         }
     }
 }
Exemple #23
0
    public static tk2dSpriteCollection CreateSpriteCollection(string basePath, string name)
    {
        string               path             = AssetDatabase.GenerateUniqueAssetPath(basePath + "/" + name + ".prefab");
        GameObject           go               = new GameObject();
        tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>();

        spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION;
        tk2dEditorUtility.SetGameObjectActive(go, false);

        PrefabUtility.SaveAsPrefabAsset(go, path);
        GameObject.DestroyImmediate(go);

        return(AssetDatabase.LoadAssetAtPath(path, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection);
    }
 public static void InitializeSpriteCollectionPlatforms(tk2dSpriteCollection gen, string root)
 {
     // Create all missing platform directories and sprite collection objects
     for (int i = 0; i < gen.platforms.Count; ++i)
     {
         tk2dSpriteCollectionPlatform plat = gen.platforms[i];
         if (plat.name.Length > 0 && !plat.spriteCollection)
         {
             plat.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, gen.name + "@" + plat.name);
             plat.spriteCollection.managedSpriteCollection = true;
             EditorUtility.SetDirty(gen.spriteCollection);
         }
     }
 }
Exemple #25
0
 public void SetGeneratorAndSelectedSprite(tk2dSpriteCollection spriteCollection, int selectedSprite)
 {
     searchFilter = "";
     SetGenerator(spriteCollection);
     foreach (var entry in entries)
     {
         if (entry.type == SpriteCollectionEditorEntry.Type.Sprite && entry.index == selectedSprite)
         {
             entry.selected = true;
             break;
         }
     }
     UpdateSelection();
 }
        public static void ValidateTextureParam(tk2dSpriteCollection gen, int i)
        {
            var param = gen.textureParams[i];

            if (param.texture != null && gen.linkParent != null)
            {
                if (gen.linkParent.textureParams[i].texture == null ||
                    gen.linkParent.textureParams[i].texture.width != param.texture.width ||
                    gen.linkParent.textureParams[i].texture.height != param.texture.height)
                {
                    Debug.LogError("Linked sprite collection mismatch " + param.texture.name);
                }
            }
        }
        public static void Build(tk2dSpriteCollection data)
        {
            if (data.linkedSpriteCollections.Count > 0 && !data.disableTrimming) {
                return;
            }

            string errors = "";
            int errorCount = 0;
            string root = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(data)) + "/Linked";
            foreach (tk2dLinkedSpriteCollection link in data.linkedSpriteCollections) {
                if (link.spriteCollection == null) {
                    if (!System.IO.Directory.Exists(root)) {
                        System.IO.Directory.CreateDirectory(root);
                    }
                    link.spriteCollection = tk2dSpriteCollectionEditor.CreateSpriteCollection(root, data.name + link.name);
                }

                tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy proxy = new tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy(data, false);
                proxy.CopyBuiltFromSource(link.spriteCollection);
                proxy.linkedSpriteCollections.Clear(); // stop recursion
                string thisErrors = "";

                foreach (tk2dSpriteCollectionDefinition tp in proxy.textureParams) {
                    if (tp.texture != null) {
                        Texture2D repl = FindReplacementTexture(tp.texture, link.name);
                        if (repl == null) {
                            thisErrors += string.Format("Unable to find replacement for texture '{0}' for link '{1}'\n", tp.texture.name, link.name);
                            ++errorCount;
                        }
                        tp.texture = repl;
                    }
                }

                if (thisErrors.Length == 0) {
                    proxy.CopyToTarget(link.spriteCollection);
                    link.spriteCollection.linkParent = data;
                    EditorUtility.SetDirty(link.spriteCollection);

                    tk2dSpriteCollectionBuilder.Rebuild(link.spriteCollection);
                }
                else {
                    errors += thisErrors;
                }
            }

            if (errors.Length > 0) {
                Debug.LogError("There were " + errorCount.ToString() + " errors building the sprite collection\n" + errors);
            }
        }
    static void TrimTextureList(tk2dSpriteCollection gen)
    {
        // trim textureRefs & textureParams
        int lastNonEmpty = -1;

        for (int i = 0; i < gen.textureRefs.Length; ++i)
        {
            if (gen.textureRefs[i] != null)
            {
                lastNonEmpty = i;
            }
        }
        System.Array.Resize(ref gen.textureRefs, lastNonEmpty + 1);
        System.Array.Resize(ref gen.textureParams, lastNonEmpty + 1);
    }
    static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex)
    {
        bool textureDirty = false;

        string          targetTexPath = AssetDatabase.GetAssetPath(tex);
        TextureImporter importer      = (TextureImporter)TextureImporter.GetAtPath(targetTexPath);

        if (gen.maxTextureSize != importer.maxTextureSize)
        {
            importer.maxTextureSize = gen.maxTextureSize;
            textureDirty            = true;
        }
        TextureImporterFormat targetFormat;

        switch (gen.textureCompression)
        {
        case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;

        case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break;

        case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break;

        default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;
        }

        if (targetFormat != importer.textureFormat)
        {
            importer.textureFormat = targetFormat;
            textureDirty           = true;
        }

        // Make sure texture is set to point filtered when no pad mode is selected
        FilterMode targetFilterMode = gen.pixelPerfectPointSampled?FilterMode.Point:FilterMode.Bilinear;

        if (tex.filterMode != targetFilterMode)
        {
            importer.filterMode = targetFilterMode;
            EditorUtility.SetDirty(importer);
            textureDirty = true;
        }


        if (textureDirty)
        {
            EditorUtility.SetDirty(importer);
            AssetDatabase.ImportAsset(targetTexPath);
        }
    }
    // Rebuild a sprite collection when out of date
    // Identifies changed textures by comparing GUID
    public static void RebuildOutOfDate(string[] changedPaths)
    {
        // This should only take existing indices, as we don't want to slow anything down here
        tk2dIndex index = tk2dEditorUtility.GetExistingIndex();

        if (index == null)
        {
            return;
        }

        tk2dSpriteCollectionData[] scg = tk2dEditorUtility.GetExistingIndex().GetSpriteCollectionData();
        if (scg == null)
        {
            return;
        }

        foreach (tk2dSpriteCollectionData thisScg in scg)
        {
            bool needRebuild = false;
            foreach (var def in thisScg.spriteDefinitions)
            {
                foreach (string changedPath in changedPaths)
                {
                    if (def.sourceTextureGUID == AssetDatabase.AssetPathToGUID(changedPath))
                    {
                        needRebuild = true;
                        break;
                    }
                }

                if (needRebuild)
                {
                    break;
                }
            }

            if (needRebuild)
            {
                tk2dSpriteCollection spriteCollectionSource = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(thisScg.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;
                if (spriteCollectionSource != null)
                {
                    Rebuild(spriteCollectionSource);
                }

                tk2dEditorUtility.UnloadUnusedAssets();
            }
        }
    }
Exemple #31
0
    public override void OnInspectorGUI()
    {
        tk2dSpriteCollection gen = (tk2dSpriteCollection)target;

        GUILayout.BeginVertical();
        GUILayout.Space(8);
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        if (GUILayout.Button("Open Editor...", EditorStyles.miniButton, GUILayout.MinWidth(120)))
        {
            tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup;
            v.SetGenerator(gen);
        }
        GUILayout.EndHorizontal();
        EditorGUILayout.EndVertical();
    }
Exemple #32
0
    public void DefaultSkin()
    {
        playerCollection = null;
        playerCollection = database.GetCollectionByName("默认皮肤");
        if (playerCollection == null)
        {
            Debug.LogWarning("加载图集失败!");
        }

        weaponCollection = null;
        weaponCollection = database.GetCollectionByName("默认武器");
        if (weaponCollection == null)
        {
            Debug.LogWarning("加载图集失败!");
        }
    }
    public override void OnInspectorGUI()
    {
        tk2dSpriteCollection gen = (tk2dSpriteCollection)target;

        GUILayout.BeginVertical();
        GUILayout.Space(8);

        if (gen.managedSpriteCollection)
        {
            string label         = showDefaultInspector?"Hide Default Inspector":"Show Default Inspector";
            int    buttonPressed = tk2dGuiUtility.InfoBoxWithButtons("This is a managed sprite collection. Please do not modify.",
                                                                     tk2dGuiUtility.WarningLevel.Info,
                                                                     new string[] { label });
            if (buttonPressed == 0)
            {
                showDefaultInspector = !showDefaultInspector;
            }
            if (showDefaultInspector)
            {
                GUILayout.Space(16);
                DrawDefaultInspector();
            }
        }
        else
        {
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Open Editor...", GUILayout.MinWidth(120)))
            {
                if (gen.name == defaultSpriteCollectionName)
                {
                    EditorUtility.DisplayDialog("Invalid Sprite Collection name", "Please rename sprite collection before proceeding", "Ok");
                }
                else
                {
                    tk2dSpriteCollectionEditorPopup v = EditorWindow.GetWindow(typeof(tk2dSpriteCollectionEditorPopup), false, "Sprite Collection Editor") as tk2dSpriteCollectionEditorPopup;
                    v.SetGenerator(gen);
                }
            }
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
        }

        EditorGUILayout.EndVertical();

        GUILayout.Space(64);
    }
Exemple #34
0
    /*
     */
    void OnEnable()
    {
        tk2dSpineSkeletonDataAsset skeletonDataAsset = target as tk2dSpineSkeletonDataAsset;

        if (skeletonDataAsset != null)
        {
            tk2dSpriteCollectionData spritesData = skeletonDataAsset.spritesData;

            if (spritesData != null)
            {
                sprites = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(spritesData.spriteCollectionGUID), typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;
            }
        }

        skeletonJSON  = serializedObject.FindProperty("skeletonJSON");
        fromAnimation = serializedObject.FindProperty("fromAnimation");
        toAnimation   = serializedObject.FindProperty("toAnimation");
        duration      = serializedObject.FindProperty("duration");
    }
Exemple #35
0
        /// <summary>
        /// Reload the collection that changed.
        /// </summary>
        public void ReloadCollection()
        {
            // safety
            if (_spriteCollectionData == null)
            {
                return;
            }

            // grab the sprite collection path
            string collectionPath = AssetDatabase.GUIDToAssetPath(_spriteCollectionData.spriteCollectionGUID);

            // reload the collection
            tk2dSpriteCollection spriteCollectionReload = AssetDatabase.LoadAssetAtPath(collectionPath, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection;

            if (spriteCollectionReload != null)
            {
                // reassign the collection instance
                _spriteCollectionData = spriteCollectionReload.spriteCollection.inst;
            }
        }
        public void DoLocalize_tk2dBaseSprite(string MainTranslation, string SecondaryTranslation)
        {
            //--[ Localize Atlas ]----------
            tk2dSpriteCollection newCollection = GetSecondaryTranslatedObj <tk2dSpriteCollection>(ref MainTranslation, ref SecondaryTranslation);

            if (newCollection != null)
            {
                if (mTarget_tk2dBaseSprite.CurrentSprite.name != MainTranslation || mTarget_tk2dBaseSprite.Collection.name != SecondaryTranslation)
                {
                    mTarget_tk2dBaseSprite.SetSprite(newCollection.spriteCollection, MainTranslation);
                }
            }
            else
            {
                if (mTarget_tk2dBaseSprite.CurrentSprite.name != MainTranslation)
                {
                    mTarget_tk2dBaseSprite.SetSprite(MainTranslation);
                }
            }
        }
    public static tk2dSpriteCollection CreateSpriteCollection(string basePath, string name)
    {
        string               path             = AssetDatabase.GenerateUniqueAssetPath(basePath + "/" + name + ".prefab");
        GameObject           go               = new GameObject();
        tk2dSpriteCollection spriteCollection = go.AddComponent <tk2dSpriteCollection>();

        spriteCollection.version = tk2dSpriteCollection.CURRENT_VERSION;
        tk2dEditorUtility.SetGameObjectActive(go, false);

#if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4)
        Object p = EditorUtility.CreateEmptyPrefab(path);
        EditorUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab);
#else
        Object p = PrefabUtility.CreateEmptyPrefab(path);
        PrefabUtility.ReplacePrefab(go, p, ReplacePrefabOptions.ConnectToPrefab);
#endif

        GameObject.DestroyImmediate(go);

        return(AssetDatabase.LoadAssetAtPath(path, typeof(tk2dSpriteCollection)) as tk2dSpriteCollection);
    }
    static void UpdateVertexCache(tk2dSpriteCollection gen, tk2dAtlas.AtlasData[] packers, tk2dSpriteCollectionData coll, List<SCGE.SpriteLut> spriteLuts)
    {
        float scale = 2.0f * gen.targetOrthoSize / gen.targetHeight;
        int padAmount = GetPadAmount(gen);

        for (int i = 0; i < sourceTextures.Length; ++i)
        {
            SCGE.SpriteLut _lut = null;
            for (int j = 0; j < spriteLuts.Count; ++j)
            {
                if (spriteLuts[j].source == i)
                {
                    _lut = spriteLuts[j];
                    break;
                }
            }

            tk2dSpriteCollectionDefinition thisTexParam = gen.textureParams[i];
            tk2dAtlas.AtlasData packer = null;
            tk2dAtlas.AtlasEntry atlasEntry = null;
            int atlasIndex = 0;
            foreach (var p in packers)
            {
                if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null)
                {
                    packer = p;
                    break;
                }
                ++atlasIndex;
            }
            float fwidth = packer.width;
            float fheight = packer.height;

            int tx = atlasEntry.x + padAmount, ty = atlasEntry.y + padAmount, tw = atlasEntry.w - padAmount * 2, th = atlasEntry.h - padAmount * 2;
            int sd_y = packer.height - ty - th;

            float uvOffsetX = 0.001f / fwidth;
            float uvOffsetY = 0.001f / fheight;

            Vector2 v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY);
            Vector2 v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY);

            Mesh mesh = null;
            Transform meshTransform = null;
            GameObject instantiated = null;

            Vector3 colliderOrigin = new Vector3();

            if (thisTexParam.overrideMesh)
            {
                // Disabled
                instantiated = GameObject.Instantiate(thisTexParam.overrideMesh) as GameObject;
                MeshFilter meshFilter = instantiated.GetComponentInChildren<MeshFilter>();
                if (meshFilter == null)
                {
                    Debug.LogError("Unable to find mesh");
                    GameObject.DestroyImmediate(instantiated);
                }
                else
                {
                    mesh = meshFilter.sharedMesh;
                    meshTransform = meshFilter.gameObject.transform;
                }
            }

            if (mesh)
            {
                coll.spriteDefinitions[i].positions = new Vector3[mesh.vertices.Length];
                coll.spriteDefinitions[i].uvs = new Vector2[mesh.vertices.Length];
                for (int j = 0; j < mesh.vertices.Length; ++j)
                {
                    coll.spriteDefinitions[i].positions[j] = meshTransform.TransformPoint(mesh.vertices[j]);
                    coll.spriteDefinitions[i].uvs[j] = new Vector2(v0.x + (v1.x - v0.x) * mesh.uv[j].x, v0.y + (v1.y - v0.y) * mesh.uv[j].y);
                }
                coll.spriteDefinitions[i].indices = new int[mesh.triangles.Length];
                for (int j = 0; j < mesh.triangles.Length; ++j)
                {
                    coll.spriteDefinitions[i].indices[j] = mesh.triangles[j];
                }
                coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex];

                GameObject.DestroyImmediate(instantiated);
            }
            else
            {
                Texture2D thisTextureRef = sourceTextures[i];

                float texHeight = thisTextureRef?thisTextureRef.height:2;
           			float texWidth = thisTextureRef?thisTextureRef.width:2;

                float h = thisTextureRef?thisTextureRef.height:64;
                float w = thisTextureRef?thisTextureRef.width:64;
                h *= thisTexParam.scale.y;
                w *= thisTexParam.scale.x;

                float scaleX = w * scale;
                float scaleY = h * scale;

                Vector3 pos0 = new Vector3(-0.5f * scaleX, 0, -0.5f * scaleY);
                switch (thisTexParam.anchor)
                {
                    case tk2dSpriteCollectionDefinition.Anchor.LowerLeft: pos0 = new Vector3(0, 0, 0); break;
                    case tk2dSpriteCollectionDefinition.Anchor.LowerCenter: pos0 = new Vector3(-0.5f * scaleX, 0, 0); break;
                    case tk2dSpriteCollectionDefinition.Anchor.LowerRight: pos0 = new Vector3(-scaleX, 0, 0); break;

                    case tk2dSpriteCollectionDefinition.Anchor.MiddleLeft: pos0 = new Vector3(0, 0, -0.5f * scaleY); break;
                    case tk2dSpriteCollectionDefinition.Anchor.MiddleCenter: pos0 = new Vector3(-0.5f * scaleX, 0, -0.5f * scaleY); break;
                    case tk2dSpriteCollectionDefinition.Anchor.MiddleRight: pos0 = new Vector3(-scaleX, 0, -0.5f * scaleY); break;

                    case tk2dSpriteCollectionDefinition.Anchor.UpperLeft: pos0 = new Vector3(0, 0, -scaleY); break;
                    case tk2dSpriteCollectionDefinition.Anchor.UpperCenter: pos0 = new Vector3(-0.5f * scaleX, 0, -scaleY); break;
                    case tk2dSpriteCollectionDefinition.Anchor.UpperRight: pos0 = new Vector3(-scaleX, 0, -scaleY); break;

                    case tk2dSpriteCollectionDefinition.Anchor.Custom:
                        {
                            pos0 = new Vector3(-thisTexParam.anchorX * thisTexParam.scale.x * scale, 0, -(h - thisTexParam.anchorY * thisTexParam.scale.y) * scale);
                        }
                        break;
                }

                colliderOrigin = new Vector3(pos0.x, pos0.z, 0.0f);
                Vector3 pos1 = pos0 + new Vector3(scaleX, 0, scaleY);

                List<Vector3> positions = new List<Vector3>();
                List<Vector2> uvs = new List<Vector2>();

                // build mesh
                if (_lut.isSplit)
                {
                    coll.spriteDefinitions[i].flipped = false; // each split could be rotated, but not consistently

                    for (int j = 0; j < spriteLuts.Count; ++j)
                    {
                        if (spriteLuts[j].source == i)
                        {
                            _lut = spriteLuts[j];

                            int thisAtlasIndex = 0;
                            foreach (var p in packers)
                            {
                                if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null)
                                {
                                    packer = p;
                                    break;
                                }
                                ++thisAtlasIndex;
                            }

                            if (thisAtlasIndex != atlasIndex)
                            {
                                // This is a serious problem, dicing is not supported when multi atlas output is selected
                                Debug.Break();
                            }

                            fwidth = packer.width;
                            fheight = packer.height;

                            tx = atlasEntry.x + padAmount;
                            ty = atlasEntry.y + padAmount;
                            tw = atlasEntry.w - padAmount * 2;
                            th = atlasEntry.h - padAmount * 2;

                            sd_y = packer.height - ty - th;
                            v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY);
                            v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY);

                            float x0 = _lut.rx / texWidth;
                            float y0 = _lut.ry / texHeight;
                            float x1 = (_lut.rx + _lut.rw) / texWidth;
                            float y1 = (_lut.ry + _lut.rh) / texHeight;

                            Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0));
                            Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1));

                            positions.Add(new Vector3(dpos0.x, dpos0.z, 0));
                            positions.Add(new Vector3(dpos1.x, dpos0.z, 0));
                            positions.Add(new Vector3(dpos0.x, dpos1.z, 0));
                            positions.Add(new Vector3(dpos1.x, dpos1.z, 0));

                            if (atlasEntry.flipped)
                            {
                                uvs.Add(new Vector2(v0.x,v0.y));
                                uvs.Add(new Vector2(v0.x,v1.y));
                                uvs.Add(new Vector2(v1.x,v0.y));
                                uvs.Add(new Vector2(v1.x,v1.y));
                            }
                            else
                            {
                                uvs.Add(new Vector2(v0.x,v0.y));
                                uvs.Add(new Vector2(v1.x,v0.y));
                                uvs.Add(new Vector2(v0.x,v1.y));
                                uvs.Add(new Vector2(v1.x,v1.y));
                            }
                        }
                    }
                }
                else
                {
                    coll.spriteDefinitions[i].flipped = atlasEntry.flipped;

                    float x0 = _lut.rx / texWidth;
                    float y0 = _lut.ry / texHeight;
                    float x1 = (_lut.rx + _lut.rw) / texWidth;
                    float y1 = (_lut.ry + _lut.rh) / texHeight;

                    Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0));
                    Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1));

                    positions.Add(new Vector3(dpos0.x, dpos0.z, 0));
                    positions.Add(new Vector3(dpos1.x, dpos0.z, 0));
                    positions.Add(new Vector3(dpos0.x, dpos1.z, 0));
                    positions.Add(new Vector3(dpos1.x, dpos1.z, 0));

                    if (atlasEntry.flipped)
                    {
                        uvs.Add(new Vector2(v0.x,v0.y));
                        uvs.Add(new Vector2(v0.x,v1.y));
                        uvs.Add(new Vector2(v1.x,v0.y));
                        uvs.Add(new Vector2(v1.x,v1.y));
                    }
                    else
                    {
                        uvs.Add(new Vector2(v0.x,v0.y));
                        uvs.Add(new Vector2(v1.x,v0.y));
                        uvs.Add(new Vector2(v0.x,v1.y));
                        uvs.Add(new Vector2(v1.x,v1.y));
                    }
                }

                // build sprite definition
                coll.spriteDefinitions[i].indices = new int[ 6 * (positions.Count / 4) ];
                for (int j = 0; j < positions.Count / 4; ++j)
                {
                    coll.spriteDefinitions[i].indices[j * 6 + 0] = j * 4 + 0;
                    coll.spriteDefinitions[i].indices[j * 6 + 1] = j * 4 + 3;
                    coll.spriteDefinitions[i].indices[j * 6 + 2] = j * 4 + 1;
                    coll.spriteDefinitions[i].indices[j * 6 + 3] = j * 4 + 2;
                    coll.spriteDefinitions[i].indices[j * 6 + 4] = j * 4 + 3;
                    coll.spriteDefinitions[i].indices[j * 6 + 5] = j * 4 + 0;
                }

                if (positions.Count > 0)
                {
                    // http://forum.unity3d.com/threads/98781-Compute-mesh-inertia-tensor-failed-for-one-of-the-actor-Behaves-differently-in-3.4
                    Vector3 p = positions[positions.Count - 1];
                    p.z -= 0.001f;
                    positions[positions.Count - 1] = p;
                }

                coll.spriteDefinitions[i].positions = new Vector3[positions.Count];
                coll.spriteDefinitions[i].uvs = new Vector2[uvs.Count];
                for (int j = 0; j < positions.Count; ++j)
                {
                    coll.spriteDefinitions[i].positions[j] = positions[j];
                    coll.spriteDefinitions[i].uvs[j] = uvs[j];
                }

                coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex];
            }

            Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f);
            Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f);
            foreach (Vector3 v in coll.spriteDefinitions[i].positions)
            {
                boundsMin = Vector3.Min(boundsMin, v);
                boundsMax = Vector3.Max(boundsMax, v);
            }

            coll.spriteDefinitions[i].boundsData = new Vector3[2];
            coll.spriteDefinitions[i].boundsData[0] = (boundsMax + boundsMin) / 2.0f;
            coll.spriteDefinitions[i].boundsData[1] = (boundsMax - boundsMin);
            coll.spriteDefinitions[i].name = gen.textureParams[i].name;

            // Generate collider data here
            UpdateColliderData(gen, coll, i, colliderOrigin);
        }
    }
        // Update target platforms
        public static void UpdatePlatformSpriteCollection(tk2dSpriteCollection source, tk2dSpriteCollection target, string dataPath, bool root, float scale, string platformName)
        {
            tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy proxy = new tk2dEditor.SpriteCollectionEditor.SpriteCollectionProxy(source);

            // Restore old sprite collection
            proxy.spriteCollection = target.spriteCollection;

            proxy.atlasTextures = target.atlasTextures;
            proxy.atlasMaterials = target.atlasMaterials;
            proxy.altMaterials = target.altMaterials;

            // This must always be zero, as children cannot have nested platforms.
            // That would open the door to a lot of unnecessary insanity
            proxy.platforms = new List<tk2dSpriteCollectionPlatform>();

            // Update atlas sizes
            proxy.atlasWidth = (int)(proxy.atlasWidth * scale);
            proxy.atlasHeight = (int)(proxy.atlasHeight * scale);
            proxy.maxTextureSize = (int)(proxy.maxTextureSize * scale);
            proxy.forcedTextureWidth = (int)(proxy.forcedTextureWidth * scale);
            proxy.forcedTextureHeight = (int)(proxy.forcedTextureHeight * scale);

            if (!proxy.useTk2dCamera)
                proxy.targetOrthoSize *= 1.0f;
            proxy.globalScale = 1.0f / scale;

            // Don't bother changing stuff on the root object
            // The root object is the one that the sprite collection is defined on initially
            if (!root)
            {
                // Update textures
                foreach (tk2dSpriteCollectionDefinition param in proxy.textureParams)
                {
                    if (param.texture == null) continue;

                    string path = AssetDatabase.GetAssetPath(param.texture);
                    string platformTexture = FindAssetForPlatform(platformName, path, textureExtensions);

                    if (platformTexture.Length == 0)
                    {
                        LogNotFoundError(platformName, param.texture.name, "texture");
                    }
                    else
                    {
                        Texture2D tex = AssetDatabase.LoadAssetAtPath(platformTexture, typeof(Texture2D)) as Texture2D;
                        if (tex == null)
                        {
                            Debug.LogError("Unable to load platform specific texture '" + platformTexture + "'");
                        }
                        else
                        {
                            param.texture = tex;
                        }
                    }

                    // Handle spritesheets. Odd coordinates could cause issues
                    if (param.extractRegion)
                    {
                        param.regionX = (int)(param.regionX * scale);
                        param.regionY = (int)(param.regionY * scale);
                        param.regionW = (int)(param.regionW * scale);
                        param.regionH = (int)(param.regionH * scale);
                    }

                    if (param.anchor == tk2dSpriteCollectionDefinition.Anchor.Custom)
                    {
                        param.anchorX = (int)(param.anchorX * scale);
                        param.anchorY = (int)(param.anchorY * scale);
                    }

                    if (param.customSpriteGeometry)
                    {
                        foreach (tk2dSpriteColliderIsland geom in param.geometryIslands)
                        {
                            for (int p = 0; p < geom.points.Length; ++p)
                                geom.points[p] *= scale;
                        }
                    }

                    if (param.colliderType == tk2dSpriteCollectionDefinition.ColliderType.Polygon)
                    {
                        foreach (tk2dSpriteColliderIsland geom in param.polyColliderIslands)
                        {
                            for (int p = 0; p < geom.points.Length; ++p)
                                geom.points[p] *= scale;
                        }
                    }
                    else if (param.colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxCustom)
                    {
                        param.boxColliderMax *= scale;
                        param.boxColliderMin *= scale;
                    }
                }
            }

            // We ALWAYS duplicate fonts
            if (target.fonts == null) target.fonts = new tk2dSpriteCollectionFont[0];
            for (int i = 0; i < proxy.fonts.Count; ++i)
            {
                tk2dSpriteCollectionFont font = proxy.fonts[i];
                if (!font.InUse || font.texture == null || font.data == null || font.editorData == null || font.bmFont == null) continue; // not valid for some reason or other
                bool needFontData = true;
                bool needFontEditorData = true;
                bool hasCorrespondingData = i < target.fonts.Length && target.fonts[i] != null;
                if (hasCorrespondingData)
                {
                    tk2dSpriteCollectionFont targetFont = target.fonts[i];
                    if (targetFont.data != null) { font.data = targetFont.data; needFontData = false; }
                    if (targetFont.editorData != null) { font.editorData = targetFont.editorData; needFontEditorData = false; }
                }

                string bmFontPath = AssetDatabase.GetAssetPath(font.bmFont);
                string texturePath = AssetDatabase.GetAssetPath(font.texture);

                if (!root)
                {
                    // find platform specific versions
                    bmFontPath = FindAssetForPlatform(platformName, bmFontPath, fontExtensions);
                    texturePath = FindAssetForPlatform(platformName, texturePath, textureExtensions);
                    if (bmFontPath.Length != 0 && texturePath.Length == 0)
                    {
                        // try to find a texture
                        tk2dEditor.Font.Info fontInfo = tk2dEditor.Font.Builder.ParseBMFont(bmFontPath);
                        if (fontInfo != null)
                            texturePath = System.IO.Path.GetDirectoryName(bmFontPath).Replace('\\', '/') + "/" + System.IO.Path.GetFileName(fontInfo.texturePaths[0]);
                    }

                    if (bmFontPath.Length == 0) LogNotFoundError(platformName, font.bmFont.name, "font");
                    if (texturePath.Length == 0) LogNotFoundError(platformName, font.texture.name, "texture");
                    if (bmFontPath.Length == 0 || texturePath.Length == 0) continue; // not found

                    // load the assets
                    font.bmFont = AssetDatabase.LoadAssetAtPath(bmFontPath, typeof(UnityEngine.Object));
                    font.texture = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D;
                }

                string targetDir = System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(target));

                // create necessary assets
                if (needFontData)
                {
                    string srcPath = AssetDatabase.GetAssetPath(font.data);
                    string destPath = AssetDatabase.GenerateUniqueAssetPath(GetCopyAtTargetPath(platformName, targetDir, srcPath));
                    AssetDatabase.CopyAsset(srcPath, destPath);
                    AssetDatabase.Refresh();
                    font.data = AssetDatabase.LoadAssetAtPath(destPath, typeof(tk2dFontData)) as tk2dFontData;
                }
                if (needFontEditorData)
                {
                    string srcPath = AssetDatabase.GetAssetPath(font.editorData);
                    string destPath = AssetDatabase.GenerateUniqueAssetPath(GetCopyAtTargetPath(platformName, targetDir, srcPath));
                    AssetDatabase.CopyAsset(srcPath, destPath);
                    AssetDatabase.Refresh();
                    font.editorData = AssetDatabase.LoadAssetAtPath(destPath, typeof(tk2dFont)) as tk2dFont;
                }

                if (font.editorData.bmFont != font.bmFont ||
                    font.editorData.texture != font.texture ||
                    font.editorData.data != font.data)
                {
                    font.editorData.bmFont = font.bmFont;
                    font.editorData.texture = font.texture;
                    font.editorData.data = font.data;
                    EditorUtility.SetDirty(font.editorData);
                }
            }

            proxy.CopyToTarget(target);
        }
 static int GetPadAmount(tk2dSpriteCollection gen)
 {
     return (gen.pixelPerfectPointSampled)?0:defaultPad;
 }
    static void SetUpSourceTextureFormats(tk2dSpriteCollection gen)
    {
        // make sure all textures are in the right format
        int numTexturesReimported = 0;
        List<Texture2D> texturesToProcess = new List<Texture2D>();

        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            if (gen.textureParams[i].texture != null)
            {
                texturesToProcess.Add(gen.textureParams[i].texture);
            }
        }
        if (gen.spriteSheets != null)
        {
            foreach (var v in gen.spriteSheets)
            {
                if (v.texture != null)
                    texturesToProcess.Add(v.texture);
            }
        }
        if (gen.fonts != null)
        {
            foreach (var v in gen.fonts)
            {
                if (v.active && v.texture != null)
                    texturesToProcess.Add(v.texture);
            }
        }
        foreach (var tex in texturesToProcess)
        {
            string thisTexturePath = AssetDatabase.GetAssetPath(tex);
            if (ConfigureSpriteTextureImporter(thisTexturePath))
            {
                numTexturesReimported++;
                AssetDatabase.ImportAsset(thisTexturePath);
            }
        }
        if (numTexturesReimported > 0)
        {
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
	void OnDisable()
	{
		ClearTextureCache();
		_spriteCollection = null;
	}
	public void SetGenerator(tk2dSpriteCollection spriteCollection)
	{
		this._spriteCollection = spriteCollection;
		this.firstRun = true;
		spriteCollectionProxy = new SpriteCollectionProxy(spriteCollection);
		PopulateEntries();
	}
    static void UpdateFontData(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, List<SpriteLut> spriteLuts, tk2dSpriteCollectionFont font, tk2dEditor.Font.Info fontInfo)
    {
        Dictionary<int, SpriteLut> glyphLut = new Dictionary<int, SpriteLut>();
        List<SpriteLut> values = new List<SpriteLut>();
        foreach (var k in glyphLut.Keys) values.Add(glyphLut[k]);

        foreach (var v in spriteLuts)
            glyphLut[v.charId] = v;
        int padAmount = GetPadAmount(gen, -1);
        foreach (var c in fontInfo.chars)
        {
            if (glyphLut.ContainsKey(c.id))
            {
                var glyphSprite = glyphLut[c.id];
                var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex);

                c.texOffsetX = glyphSprite.rx;
                c.texOffsetY = glyphSprite.ry;

                c.texX = atlasEntry.x + padAmount;
                c.texY = atlasEntry.y + padAmount;
                c.texW = atlasEntry.w - padAmount * 2;
                c.texH = atlasEntry.h - padAmount * 2;
                c.texFlipped = atlasEntry.flipped;
            }
            else
            {
                var glyphSprite = glyphLut[-1];
                var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex);

                c.texOffsetX = 0;
                c.texOffsetY = 0;

                c.texX = atlasEntry.x + 1;
                c.texY = atlasEntry.y + 1;
                c.texW = 0;
                c.texH = 0;
                c.texFlipped = false;
            }
            c.texOverride = true;
        }

        tk2dEditor.Font.Builder.BuildFont(fontInfo, font.data, scale, font.charPadX, font.dupeCaps, false, null, 0);
    }
    static void SetUpSourceTextureFormats(tk2dSpriteCollection gen)
    {
        // make sure all textures are in the right format
        int numTexturesReimported = 0;
        List<Texture2D> texturesToProcess = new List<Texture2D>();

        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            if (gen.textureRefs[i] != null)
            {
                texturesToProcess.Add(gen.textureRefs[i]);
            }
        }
        if (gen.spriteSheets != null)
        {
            for (int i = 0; i < gen.spriteSheets.Length; ++i)
            {
                if (gen.spriteSheets[i].texture != null)
                {
                    texturesToProcess.Add(gen.spriteSheets[i].texture);
                }
            }
        }
        foreach (var tex in texturesToProcess)
        {
            // make sure the source texture is npot and readable, and uncompressed
            string thisTextPath = AssetDatabase.GetAssetPath(tex);
            TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(thisTextPath);
            if (importer.textureType != TextureImporterType.Advanced ||
                importer.textureFormat != TextureImporterFormat.AutomaticTruecolor ||
                importer.npotScale != TextureImporterNPOTScale.None ||
                importer.isReadable != true ||
                importer.maxTextureSize < 4096)
            {
                importer.textureFormat = TextureImporterFormat.AutomaticTruecolor;
                importer.textureType = TextureImporterType.Advanced;
                importer.npotScale = TextureImporterNPOTScale.None;
                importer.isReadable = true;
                importer.mipmapEnabled = false;
                importer.maxTextureSize = 4096;

                AssetDatabase.ImportAsset(thisTextPath);

                numTexturesReimported++;
            }
        }
        if (numTexturesReimported > 0)
        {
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }
    }
    static void UpdateVertexCache(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, tk2dSpriteCollectionData coll, List<SpriteLut> spriteLuts)
    {
        for (int i = 0; i < sourceTextures.Length; ++i)
        {
            SpriteLut _lut = null;
            for (int j = 0; j < spriteLuts.Count; ++j)
            {
                if (spriteLuts[j].source == i)
                {
                    _lut = spriteLuts[j];
                    break;
                }
            }

            int padAmount = GetPadAmount(gen, i);

            tk2dSpriteCollectionDefinition thisTexParam = gen.textureParams[i];
            tk2dEditor.Atlas.Data packer = null;
            tk2dEditor.Atlas.Entry atlasEntry = null;
            int atlasIndex = 0;
            foreach (var p in packers)
            {
                if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null)
                {
                    packer = p;
                    break;
                }
                ++atlasIndex;
            }
            float fwidth = packer.width;
            float fheight = packer.height;

            int tx = atlasEntry.x + padAmount, ty = atlasEntry.y + padAmount, tw = atlasEntry.w - padAmount * 2, th = atlasEntry.h - padAmount * 2;
            int sd_y = packer.height - ty - th;

            float uvOffsetX = 0.001f / fwidth;
            float uvOffsetY = 0.001f / fheight;

            Vector2 v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY);
            Vector2 v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY);

            Mesh mesh = null;
            Transform meshTransform = null;
            GameObject instantiated = null;

            Vector3 colliderOrigin = new Vector3();

            if (thisTexParam.overrideMesh)
            {
                // Disabled
                instantiated = GameObject.Instantiate(thisTexParam.overrideMesh) as GameObject;
                MeshFilter meshFilter = instantiated.GetComponentInChildren<MeshFilter>();
                if (meshFilter == null)
                {
                    Debug.LogError("Unable to find mesh");
                    GameObject.DestroyImmediate(instantiated);
                }
                else
                {
                    mesh = meshFilter.sharedMesh;
                    meshTransform = meshFilter.gameObject.transform;
                }
            }

            Vector3 untrimmedPos0 = Vector3.zero, untrimmedPos1 = Vector3.one;

            if (mesh)
            {
                coll.spriteDefinitions[i].positions = new Vector3[mesh.vertices.Length];
                coll.spriteDefinitions[i].uvs = new Vector2[mesh.vertices.Length];
                for (int j = 0; j < mesh.vertices.Length; ++j)
                {
                    coll.spriteDefinitions[i].positions[j] = meshTransform.TransformPoint(mesh.vertices[j]);
                    coll.spriteDefinitions[i].uvs[j] = new Vector2(v0.x + (v1.x - v0.x) * mesh.uv[j].x, v0.y + (v1.y - v0.y) * mesh.uv[j].y);
                }
                coll.spriteDefinitions[i].indices = new int[mesh.triangles.Length];
                for (int j = 0; j < mesh.triangles.Length; ++j)
                {
                    coll.spriteDefinitions[i].indices[j] = mesh.triangles[j];
                }
                GameObject.DestroyImmediate(instantiated);
            }
            else
            {
                Texture2D thisTextureRef = sourceTextures[i];

                int texHeightI = thisTextureRef?thisTextureRef.height:2;
                int texWidthI = thisTextureRef?thisTextureRef.width:2;
                float texHeight = texHeightI;
           			float texWidth = texWidthI;

                float h = thisTextureRef?thisTextureRef.height:64;
                float w = thisTextureRef?thisTextureRef.width:64;
                h *= thisTexParam.scale.y;
                w *= thisTexParam.scale.x;

                float scaleX = w * scale;
                float scaleY = h * scale;

                // anchor coordinate system is (0, 0) = top left, to keep it the same as photoshop, etc.
                switch (thisTexParam.anchor)
                {
                    case tk2dSpriteCollectionDefinition.Anchor.LowerLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI; break;
                    case tk2dSpriteCollectionDefinition.Anchor.LowerCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI; break;
                    case tk2dSpriteCollectionDefinition.Anchor.LowerRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI; break;

                    case tk2dSpriteCollectionDefinition.Anchor.MiddleLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = texHeightI / 2; break;
                    case tk2dSpriteCollectionDefinition.Anchor.MiddleCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = texHeightI / 2; break;
                    case tk2dSpriteCollectionDefinition.Anchor.MiddleRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = texHeightI / 2; break;

                    case tk2dSpriteCollectionDefinition.Anchor.UpperLeft: thisTexParam.anchorX = 0; thisTexParam.anchorY = 0; break;
                    case tk2dSpriteCollectionDefinition.Anchor.UpperCenter: thisTexParam.anchorX = texWidthI / 2; thisTexParam.anchorY = 0; break;
                    case tk2dSpriteCollectionDefinition.Anchor.UpperRight: thisTexParam.anchorX = texWidthI; thisTexParam.anchorY = 0; break;
                }
                Vector3 pos0 = new Vector3(-thisTexParam.anchorX * thisTexParam.scale.x * scale, 0, -(h - thisTexParam.anchorY * thisTexParam.scale.y) * scale);

                colliderOrigin = new Vector3(pos0.x, pos0.z, 0.0f);
                Vector3 pos1 = pos0 + new Vector3(scaleX, 0, scaleY);

                untrimmedPos0 = new Vector3(pos0.x, pos0.z);
                untrimmedPos1 = new Vector3(pos1.x, pos1.z);

                List<Vector3> positions = new List<Vector3>();
                List<Vector2> uvs = new List<Vector2>();

                // build mesh
                if (_lut.isSplit)
                {
                    coll.spriteDefinitions[i].flipped = false; // each split could be rotated, but not consistently

                    for (int j = 0; j < spriteLuts.Count; ++j)
                    {
                        if (spriteLuts[j].source == i)
                        {
                            _lut = spriteLuts[j];

                            int thisAtlasIndex = 0;
                            foreach (var p in packers)
                            {
                                if ((atlasEntry = p.FindEntryWithIndex(_lut.atlasIndex)) != null)
                                {
                                    packer = p;
                                    break;
                                }
                                ++thisAtlasIndex;
                            }

                            if (thisAtlasIndex != atlasIndex)
                            {
                                // This is a serious problem, dicing is not supported when multi atlas output is selected
                                Debug.Break();
                            }

                            fwidth = packer.width;
                            fheight = packer.height;

                            tx = atlasEntry.x + padAmount;
                            ty = atlasEntry.y + padAmount;
                            tw = atlasEntry.w - padAmount * 2;
                            th = atlasEntry.h - padAmount * 2;

                            sd_y = packer.height - ty - th;
                            v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY);
                            v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY);

                            float x0 = _lut.rx / texWidth;
                            float y0 = _lut.ry / texHeight;
                            float x1 = (_lut.rx + _lut.rw) / texWidth;
                            float y1 = (_lut.ry + _lut.rh) / texHeight;

                            Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0));
                            Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1));

                            positions.Add(new Vector3(dpos0.x, dpos0.z, 0));
                            positions.Add(new Vector3(dpos1.x, dpos0.z, 0));
                            positions.Add(new Vector3(dpos0.x, dpos1.z, 0));
                            positions.Add(new Vector3(dpos1.x, dpos1.z, 0));

                            if (atlasEntry.flipped)
                            {
                                uvs.Add(new Vector2(v0.x,v0.y));
                                uvs.Add(new Vector2(v0.x,v1.y));
                                uvs.Add(new Vector2(v1.x,v0.y));
                                uvs.Add(new Vector2(v1.x,v1.y));
                            }
                            else
                            {
                                uvs.Add(new Vector2(v0.x,v0.y));
                                uvs.Add(new Vector2(v1.x,v0.y));
                                uvs.Add(new Vector2(v0.x,v1.y));
                                uvs.Add(new Vector2(v1.x,v1.y));
                            }
                        }
                    }
                }
                else if (thisTexParam.customSpriteGeometry)
                {
                    coll.spriteDefinitions[i].flipped = atlasEntry.flipped;

                    List<int> indices = new List<int>();
                    foreach (var island in thisTexParam.geometryIslands)
                    {
                        int baseIndex = positions.Count;
                        for (int x = 0; x < island.points.Length; ++x)
                        {
                            var v = island.points[x];
                            Vector2 origin = new Vector2(pos0.x, pos0.z);
                            positions.Add(new Vector2(v.x * thisTexParam.scale.x, (texHeight - v.y) * thisTexParam.scale.y) * scale + new Vector2(origin.x, origin.y));

                            tx = atlasEntry.x + padAmount;
                            ty = atlasEntry.y + padAmount;
                            tw = atlasEntry.w - padAmount * 2;
                            th = atlasEntry.h - padAmount * 2;

                            //v0 = new Vector2(tx / fwidth + uvOffsetX, 1.0f - (sd_y + th) / fheight + uvOffsetY);
                            //v1 = new Vector2((tx + tw) / fwidth - uvOffsetX, 1.0f - sd_y / fheight - uvOffsetY);

                            Vector2 uv = new Vector2();
                            if (atlasEntry.flipped)
                            {
                                uv.x = (tx - _lut.ry + texHeight - v.y) / fwidth + uvOffsetX;
                                uv.y = (ty - _lut.rx + v.x) / fheight + uvOffsetY;
                            }
                            else
                            {
                                uv.x = (tx - _lut.rx + v.x) / fwidth + uvOffsetX;
                                uv.y = (ty - _lut.ry + texHeight - v.y) / fheight + uvOffsetY ;
                            }

                            uvs.Add(uv);
                        }

                        tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(island.points);
                        int[] localIndices = triangulator.Triangulate();
                        //for (int x = localIndices.Length - 1; x >= 0; --x)
                        for (int x = 0; x < localIndices.Length; x += 3)
                        {
                            indices.Add(baseIndex + localIndices[x + 2]);
                            indices.Add(baseIndex + localIndices[x + 1]);
                            indices.Add(baseIndex + localIndices[x + 0]);
                        }
                    }

                    coll.spriteDefinitions[i].indices = indices.ToArray();
                }
                else
                {
                    coll.spriteDefinitions[i].flipped = atlasEntry.flipped;

                    float x0 = _lut.rx / texWidth;
                    float y0 = _lut.ry / texHeight;
                    float x1 = (_lut.rx + _lut.rw) / texWidth;
                    float y1 = (_lut.ry + _lut.rh) / texHeight;

                    Vector3 dpos0 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x0), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y0));
                    Vector3 dpos1 = new Vector3(Mathf.Lerp(pos0.x, pos1.x, x1), 0.0f, Mathf.Lerp(pos0.z, pos1.z, y1));

                    positions.Add(new Vector3(dpos0.x, dpos0.z, 0));
                    positions.Add(new Vector3(dpos1.x, dpos0.z, 0));
                    positions.Add(new Vector3(dpos0.x, dpos1.z, 0));
                    positions.Add(new Vector3(dpos1.x, dpos1.z, 0));

                    if (atlasEntry.flipped)
                    {
                        uvs.Add(new Vector2(v0.x,v0.y));
                        uvs.Add(new Vector2(v0.x,v1.y));
                        uvs.Add(new Vector2(v1.x,v0.y));
                        uvs.Add(new Vector2(v1.x,v1.y));
                    }
                    else
                    {
                        uvs.Add(new Vector2(v0.x,v0.y));
                        uvs.Add(new Vector2(v1.x,v0.y));
                        uvs.Add(new Vector2(v0.x,v1.y));
                        uvs.Add(new Vector2(v1.x,v1.y));
                    }
                }

                // build sprite definition
                if (!thisTexParam.customSpriteGeometry)
                {
                    coll.spriteDefinitions[i].indices = new int[ 6 * (positions.Count / 4) ];
                    for (int j = 0; j < positions.Count / 4; ++j)
                    {
                        coll.spriteDefinitions[i].indices[j * 6 + 0] = j * 4 + 0;
                        coll.spriteDefinitions[i].indices[j * 6 + 1] = j * 4 + 3;
                        coll.spriteDefinitions[i].indices[j * 6 + 2] = j * 4 + 1;
                        coll.spriteDefinitions[i].indices[j * 6 + 3] = j * 4 + 2;
                        coll.spriteDefinitions[i].indices[j * 6 + 4] = j * 4 + 3;
                        coll.spriteDefinitions[i].indices[j * 6 + 5] = j * 4 + 0;
                    }
                    coll.spriteDefinitions[i].complexGeometry = false;
                }
                else
                {
                    coll.spriteDefinitions[i].complexGeometry = true;
                }

                // This doesn't seem to be necessary in UNITY_3_5_3
        #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5_0 || UNITY_3_5_1 || UNITY_3_5_2)
                if (positions.Count > 0)
                {
                    // http://forum.unity3d.com/threads/98781-Compute-mesh-inertia-tensor-failed-for-one-of-the-actor-Behaves-differently-in-3.4
                    Vector3 p = positions[positions.Count - 1];
                    p.z -= 0.001f;
                    positions[positions.Count - 1] = p;
                }
        #endif

                coll.spriteDefinitions[i].positions = new Vector3[positions.Count];
                coll.spriteDefinitions[i].uvs = new Vector2[uvs.Count];
                for (int j = 0; j < positions.Count; ++j)
                {
                    coll.spriteDefinitions[i].positions[j] = positions[j];
                    coll.spriteDefinitions[i].uvs[j] = uvs[j];
                }

                // empty out to a sensible default, which corresponds to what Unity does by default
                coll.spriteDefinitions[i].normals = new Vector3[0];
                coll.spriteDefinitions[i].tangents = new Vector4[0];

                // fill out tangents and normals
                if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.None)
                {
                    Mesh tmpMesh = new Mesh();
                    tmpMesh.vertices = coll.spriteDefinitions[i].positions;
                    tmpMesh.uv = coll.spriteDefinitions[i].uvs;
                    tmpMesh.triangles = coll.spriteDefinitions[i].indices;

                    tmpMesh.RecalculateNormals();

                    coll.spriteDefinitions[i].normals = tmpMesh.normals;

                    if (gen.normalGenerationMode != tk2dSpriteCollection.NormalGenerationMode.NormalsOnly)
                    {
                        coll.spriteDefinitions[i].tangents = tmpMesh.tangents;
                    }
                }
            }

            // fixup in case something went wrong
            if (coll.allowMultipleAtlases)
            {
                coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex];
            }
            else
            {
                coll.spriteDefinitions[i].material = gen.altMaterials[thisTexParam.materialId];
                coll.spriteDefinitions[i].materialId = thisTexParam.materialId;

                if (coll.spriteDefinitions[i].material == null) // fall back gracefully in case something went wrong
                {
                    coll.spriteDefinitions[i].material = gen.atlasMaterials[atlasIndex];
                    coll.spriteDefinitions[i].materialId = 0;
                }
            }

            Vector3 boundsMin = new Vector3(1.0e32f, 1.0e32f, 1.0e32f);
            Vector3 boundsMax = new Vector3(-1.0e32f, -1.0e32f, -1.0e32f);
            foreach (Vector3 v in coll.spriteDefinitions[i].positions)
            {
                boundsMin = Vector3.Min(boundsMin, v);
                boundsMax = Vector3.Max(boundsMax, v);
            }

            coll.spriteDefinitions[i].boundsData = new Vector3[2];
            coll.spriteDefinitions[i].boundsData[0] = (boundsMax + boundsMin) / 2.0f;
            coll.spriteDefinitions[i].boundsData[1] = (boundsMax - boundsMin);

            // this is the dimension of exactly one pixel, scaled to match sprite dimensions and scale
            coll.spriteDefinitions[i].texelSize = new Vector3(scale * thisTexParam.scale.x, scale * thisTexParam.scale.y, 0.0f);

            coll.spriteDefinitions[i].untrimmedBoundsData = new Vector3[2];
            if (mesh)
            {
                // custom meshes aren't trimmed, the untrimmed bounds are exactly the same as the regular ones
                coll.spriteDefinitions[i].untrimmedBoundsData[0] = coll.spriteDefinitions[i].boundsData[0];
                coll.spriteDefinitions[i].untrimmedBoundsData[1] = coll.spriteDefinitions[i].boundsData[1];
            }
            else
            {
                boundsMin = Vector3.Min(untrimmedPos0, untrimmedPos1);
                boundsMax = Vector3.Max(untrimmedPos0, untrimmedPos1);
                coll.spriteDefinitions[i].untrimmedBoundsData[0] = (boundsMax + boundsMin) / 2.0f;
                coll.spriteDefinitions[i].untrimmedBoundsData[1] = (boundsMax - boundsMin);
            }

            coll.spriteDefinitions[i].name = gen.textureParams[i].name;

            // Generate collider data here
            UpdateColliderData(gen, scale, coll, i, colliderOrigin);
        }
    }
    static void UpdateFontData(tk2dSpriteCollection gen, float scale, tk2dEditor.Atlas.Data[] packers, List<SpriteLut> spriteLuts, tk2dSpriteCollectionFont font, tk2dEditor.Font.Info fontInfo)
    {
        Dictionary<int, SpriteLut> glyphLut = new Dictionary<int, SpriteLut>();
        List<SpriteLut> values = new List<SpriteLut>();
        foreach (var k in glyphLut.Keys) values.Add(glyphLut[k]);

        foreach (var v in spriteLuts)
            glyphLut[v.charId] = v;
        int padAmount = GetPadAmount(gen, -1);
        foreach (var c in fontInfo.chars)
        {
            if (glyphLut.ContainsKey(c.id))
            {
                var glyphSprite = glyphLut[c.id];
                var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex);

                c.texOffsetX = glyphSprite.rx;

                if (font.flipTextureY)
                {
                    // This is the offset from the bottom of the font
                    c.texOffsetY = glyphSprite.ry;
                }
                else
                {
                    // ry is offset from top, we want offset from bottom
                    // height is the original glyph height before cropping, the remainder of which is
                    // the offset from bottom
                    c.texOffsetY = c.height - glyphSprite.rh - glyphSprite.ry;
                }

                c.texX = atlasEntry.x + padAmount;
                c.texY = atlasEntry.y + padAmount;
                c.texW = atlasEntry.w - padAmount * 2;
                c.texH = atlasEntry.h - padAmount * 2;
                c.texFlipped = atlasEntry.flipped;
            }
            else
            {
                var glyphSprite = glyphLut[-1];
                var atlasEntry = packers[0].FindEntryWithIndex(glyphSprite.atlasIndex);

                c.texOffsetX = 0;
                c.texOffsetY = 0;

                c.texX = atlasEntry.x + 1;
                c.texY = atlasEntry.y + 1;
                c.texW = 0;
                c.texH = 0;
                c.texFlipped = false;
            }
            c.texOverride = true;
        }

        tk2dEditor.Font.Builder.BuildFont(fontInfo, font.data, scale, font.charPadX, font.dupeCaps, font.flipTextureY, font.gradientTexture, font.gradientCount);
    }
    static void UpdateColliderData(tk2dSpriteCollection gen, float scale, tk2dSpriteCollectionData coll, int spriteIndex, Vector3 origin)
    {
        var colliderType = gen.textureParams[spriteIndex].colliderType;
        var def = coll.spriteDefinitions[spriteIndex];
        var src = gen.textureParams[spriteIndex];

        def.colliderVertices = null;
        def.colliderIndicesFwd = null;
        def.colliderIndicesBack = null;

        float texHeight = 0;
        if (src.extractRegion)
        {
            texHeight = src.regionH;
        }
        else
        {
            texHeight = gen.textureParams[spriteIndex].texture?gen.textureParams[spriteIndex].texture.height:2.0f;
        }

        if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxTrimmed)
        {
            def.colliderVertices = new Vector3[2];
            def.colliderVertices[0] = def.boundsData[0];
            def.colliderVertices[1] = def.boundsData[1] * 0.5f; // extents is 1/2x size
            def.colliderVertices[1].z = gen.physicsDepth;
            def.colliderType = tk2dSpriteDefinition.ColliderType.Box;
        }
        else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.BoxCustom)
        {
            Vector2 v0 = new Vector3(src.boxColliderMin.x * src.scale.x, (texHeight - src.boxColliderMax.y) * src.scale.y) * scale + origin;
            Vector2 v1 = new Vector3(src.boxColliderMax.x * src.scale.x, (texHeight - src.boxColliderMin.y) * src.scale.y) * scale + origin;

            def.colliderVertices = new Vector3[2];
            def.colliderVertices[0] = (v0 + v1) * 0.5f;
            def.colliderVertices[1] = (v1 - v0) * 0.5f;
            def.colliderVertices[1].z = gen.physicsDepth;
            def.colliderType = tk2dSpriteDefinition.ColliderType.Box;
        }
        else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.Polygon)
        {
            List<Vector3> meshVertices = new List<Vector3>();
            List<int> meshIndicesFwd = new List<int>();

            foreach (var island in src.polyColliderIslands)
            {
                List<Vector2> points = new List<Vector2>();
                List<Vector2> points2D = new List<Vector2>();

                // List all points
                for (int i = 0; i < island.points.Length; ++i)
                {
                    Vector2 v = island.points[i];
                    points.Add(new Vector2(v.x * src.scale.x, (texHeight - v.y) * src.scale.y) * scale + new Vector2(origin.x, origin.y));
                }

                int baseIndex = meshVertices.Count;
                for (int i = 0; i < points.Count; ++i)
                {
                    meshVertices.Add( new Vector3(points[i].x, points[i].y, -gen.physicsDepth) );
                    meshVertices.Add( new Vector3(points[i].x, points[i].y,  gen.physicsDepth) );
                    points2D.Add( new Vector2(points[i].x, points[i].y) );
                }

                // body
                int numPoints = island.connected?points.Count:(points.Count - 1);
                for (int i = 0; i < numPoints; ++i)
                {
                    int i0 = i * 2;
                    int i1 = i0 + 1;
                    int i2 = ((i + 1)%island.points.Length) * 2;
                    int i3 = i2 + 1;

                    // Classify primary edge direction, and flip accordingly
                    bool flipIndices = false;
                    Vector2 grad = points2D[i] - points2D[(i + 1) % points2D.Count];
                    if (Mathf.Abs(grad.x) < Mathf.Abs(grad.y))
                    {
                        flipIndices = (grad.y > 0.0f);
                    }
                    else
                    {
                        flipIndices = (grad.x > 0.0f);
                    }

                    if (flipIndices)
                    {
                        meshIndicesFwd.Add(baseIndex + i2);
                        meshIndicesFwd.Add(baseIndex + i3);
                        meshIndicesFwd.Add(baseIndex + i0);
                        meshIndicesFwd.Add(baseIndex + i0);
                        meshIndicesFwd.Add(baseIndex + i3);
                        meshIndicesFwd.Add(baseIndex + i1);
                    }
                    else
                    {
                        meshIndicesFwd.Add(baseIndex + i2);
                        meshIndicesFwd.Add(baseIndex + i1);
                        meshIndicesFwd.Add(baseIndex + i0);
                        meshIndicesFwd.Add(baseIndex + i2);
                        meshIndicesFwd.Add(baseIndex + i3);
                        meshIndicesFwd.Add(baseIndex + i1);
                    }
                }

                // cap if allowed and necessary
                var cap = src.polyColliderCap;
                if (island.connected && cap != tk2dSpriteCollectionDefinition.PolygonColliderCap.None)
                {
                    tk2dEditor.Triangulator triangulator = new tk2dEditor.Triangulator(points2D.ToArray());
                    int[] indices = triangulator.Triangulate();

                    if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Front || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack)
                    {
                        for (int i = 0; i < indices.Length; ++i)
                            meshIndicesFwd.Add(baseIndex + indices[i] * 2);
                    }

                    if (cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.Back || cap == tk2dSpriteCollectionDefinition.PolygonColliderCap.FrontAndBack)
                    {
                        for (int i = 0; i < indices.Length; i += 3)
                        {
                            meshIndicesFwd.Add(baseIndex + indices[i + 2] * 2 + 1);
                            meshIndicesFwd.Add(baseIndex + indices[i + 1] * 2 + 1);
                            meshIndicesFwd.Add(baseIndex + indices[i + 0] * 2 + 1);
                        }
                    }
                }
            }

            int[] meshIndicesBack = new int[meshIndicesFwd.Count];
            for (int i = 0; i < meshIndicesFwd.Count; i += 3)
            {
                meshIndicesBack[i + 0] = meshIndicesFwd[i + 2];
                meshIndicesBack[i + 1] = meshIndicesFwd[i + 1];
                meshIndicesBack[i + 2] = meshIndicesFwd[i + 0];
            }

            def.colliderVertices = meshVertices.ToArray();
            def.colliderIndicesFwd = meshIndicesFwd.ToArray();
            def.colliderIndicesBack = meshIndicesBack;
            def.colliderConvex = src.colliderConvex;
            def.colliderType = tk2dSpriteDefinition.ColliderType.Mesh;
            def.colliderSmoothSphereCollisions = src.colliderSmoothSphereCollisions;
        }
        else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.ForceNone)
        {
            def.colliderType = tk2dSpriteDefinition.ColliderType.None;
        }
        else if (colliderType == tk2dSpriteCollectionDefinition.ColliderType.UserDefined)
        {
            def.colliderType = tk2dSpriteDefinition.ColliderType.Unset;
        }
    }
    static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex)
    {
        bool textureDirty = false;

        string targetTexPath = AssetDatabase.GetAssetPath(tex);
        TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(targetTexPath);
        if (gen.maxTextureSize != importer.maxTextureSize)
        {
            importer.maxTextureSize = gen.maxTextureSize;
            textureDirty = true;
        }
        TextureImporterFormat targetFormat;
        switch (gen.textureCompression)
        {
        case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;
        case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Dithered16Bit_Alpha: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Dithered16Bit_NoAlpha: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break;

        default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;
        }

        if (targetFormat != importer.textureFormat)
        {
            importer.textureFormat = targetFormat;
            textureDirty = true;
        }

        if (importer.filterMode != gen.filterMode)
        {
            importer.filterMode = gen.filterMode; textureDirty = true;
        }

        if (!gen.userDefinedTextureSettings)
        {
            if (importer.wrapMode != gen.wrapMode) { importer.wrapMode = gen.wrapMode; textureDirty = true; }
            if (importer.mipmapEnabled != gen.mipmapEnabled) { importer.mipmapEnabled = gen.mipmapEnabled; textureDirty = true; }
            if (importer.anisoLevel != gen.anisoLevel) { importer.anisoLevel = gen.anisoLevel; textureDirty = true; }
        }

        if (textureDirty)
        {
            EditorUtility.SetDirty(importer);
            AssetDatabase.ImportAsset(targetTexPath);
        }
    }
    public static bool Rebuild(tk2dSpriteCollection gen)
    {
        // avoid "recursive" build being triggered by texture watcher
        if (currentBuild != null)
            return false;

        currentBuild = gen;

        List<Texture2D> allocatedTextures = new List<Texture2D>();
        string path = AssetDatabase.GetAssetPath(gen);
        string subDirName = Path.GetDirectoryName( path.Substring(7) );
        if (subDirName.Length > 0) subDirName += "/";

        string dataDirFullPath = Application.dataPath + "/" + subDirName + Path.GetFileNameWithoutExtension(path) + "_Data";
        string dataDirName = "Assets/" + dataDirFullPath.Substring( Application.dataPath.Length + 1 ) + "/";

        if (gen.atlasTextures == null || gen.atlasTextures.Length == 0 ||
            gen.atlasMaterials == null || gen.atlasMaterials.Length == 0 ||
            gen.spriteCollection == null)
        {
            if (!Directory.Exists(dataDirFullPath)) Directory.CreateDirectory(dataDirFullPath);
            AssetDatabase.Refresh();
        }

        string prefabObjectPath = gen.spriteCollection?AssetDatabase.GetAssetPath(gen.spriteCollection):(dataDirName + "data.prefab");

          	if (!CheckAndFixUpParams(gen))
        {
            // Params failed check
            return false;
        }

        SetUpSourceTextureFormats(gen);
        SetUpSpriteSheets(gen);
        TrimTextureList(gen);

        // blank texture used when texture has been deleted
        Texture2D blankTexture = new Texture2D(2, 2);
        blankTexture.SetPixel(0, 0, Color.magenta);
        blankTexture.SetPixel(0, 1, Color.yellow);
        blankTexture.SetPixel(1, 0, Color.cyan);
        blankTexture.SetPixel(1, 1, Color.grey);
        blankTexture.Apply();

        // make local texture sources
        sourceTextures = new Texture2D[gen.textureRefs.Length];
        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            var param = gen.textureParams[i];
            if (param.extractRegion && gen.textureRefs[i] != null)
            {
                Texture2D localTex = new Texture2D(param.regionW, param.regionH);
                for (int y = 0; y < param.regionH; ++y)
                {
                    for (int x = 0; x < param.regionW; ++x)
                    {
                        localTex.SetPixel(x, y, gen.textureRefs[i].GetPixel(param.regionX + x, param.regionY + y));
                    }
                }
                localTex.name = gen.textureRefs[i].name + "/" + param.regionId.ToString();
                localTex.Apply();
                allocatedTextures.Add(localTex);
                sourceTextures[i] = localTex;
            }
            else
            {
                sourceTextures[i] = gen.textureRefs[i];
            }
        }

        // catalog all textures to atlas
        int numTexturesToAtlas = 0;
        List<SpriteLut> spriteLuts = new List<SpriteLut>();
        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            Texture2D currentTexture = sourceTextures[i];

            if (sourceTextures[i] == null)
            {
                gen.textureParams[i].dice = false;
                gen.textureParams[i].anchor = tk2dSpriteCollectionDefinition.Anchor.MiddleCenter;
                gen.textureParams[i].name = "";
                gen.textureParams[i].extractRegion = false;
                gen.textureParams[i].fromSpriteSheet = false;

                currentTexture = blankTexture;
            }
            else
            {
                if (gen.textureParams[i].name == null || gen.textureParams[i].name == "")
                {
                    if (gen.textureParams[i].texture != currentTexture && !gen.textureParams[i].fromSpriteSheet)
                    {
                        gen.textureParams[i].name = currentTexture.name;
                    }
                }
            }

            gen.textureParams[i].texture = currentTexture;

            if (gen.textureParams[i].dice)
            {
                // prepare to dice this up
                int diceUnitX = gen.textureParams[i].diceUnitX;
                int diceUnitY = gen.textureParams[i].diceUnitY;
                if (diceUnitX <= 0) diceUnitX = 128; // something sensible, please
                if (diceUnitY <= 0) diceUnitY = diceUnitX; // make square if not set

                Texture2D srcTex = currentTexture;
                for (int sx = 0; sx < srcTex.width; sx += diceUnitX)
                {
                    for (int sy = 0; sy < srcTex.height; sy += diceUnitY)
                    {
                        int tw = Mathf.Min(diceUnitX, srcTex.width - sx);
                        int th = Mathf.Min(diceUnitY, srcTex.height - sy);

                        SpriteLut diceLut = new SpriteLut();
                        diceLut.source = i;
                        diceLut.isSplit = true;
                        diceLut.sourceTex = srcTex;
                        diceLut.isDuplicate = false; // duplicate diced textures can be chopped up differently, so don't detect dupes here

                        Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, true, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen, i));
                        if (dest)
                        {
                            diceLut.atlasIndex = numTexturesToAtlas++;
                            spriteLuts.Add(diceLut);
                        }
                    }
                }
            }
            else
            {
                SpriteLut lut = new SpriteLut();
                lut.sourceTex = currentTexture;
                lut.source = i;

                lut.isSplit = false;
                lut.isDuplicate = false;
                for (int j = 0; j < spriteLuts.Count; ++j)
                {
                    if (spriteLuts[j].sourceTex == lut.sourceTex)
                    {
                        lut.isDuplicate = true;
                        lut.atlasIndex = spriteLuts[j].atlasIndex;
                        lut.tex = spriteLuts[j].tex; // get old processed tex

                        lut.rx = spriteLuts[j].rx; lut.ry = spriteLuts[j].ry;
                        lut.rw = spriteLuts[j].rw; lut.rh = spriteLuts[j].rh;

                        break;
                    }
                }

                if (!lut.isDuplicate)
                {
                    lut.atlasIndex = numTexturesToAtlas++;
                    bool stretchPad = false;
                    if (gen.textureParams[i].pad == tk2dSpriteCollectionDefinition.Pad.Extend) stretchPad = true;

                    Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, stretchPad, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen, i));
                    if (dest == null)
                    {
                        // fall back to a tiny blank texture
                        lut.tex = new Texture2D(1, 1);
                        lut.tex.SetPixel(0, 0, new Color( 0, 0, 0, 0 ));
                        PadTexture(lut.tex, GetPadAmount(gen, i), stretchPad);
                        lut.tex.Apply();

                        lut.rx = currentTexture.width / 2; lut.ry = currentTexture.height / 2;
                        lut.rw = 1; lut.rh = 1;
                    }
                }

                spriteLuts.Add(lut);
            }
        }

        // Font
        Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info> fontInfoDict = new Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info>();
        if (gen.fonts != null)
        {
            for (int i = 0; i < gen.fonts.Length; ++i)
            {
                var font = gen.fonts[i];
                if (!font.InUse) continue;

                var fontInfo = tk2dEditor.Font.Builder.ParseBMFont( AssetDatabase.GetAssetPath(font.bmFont) );
                fontInfoDict[font] = fontInfo;
                foreach (var c in fontInfo.chars)
                {
                    // skip empty textures
                    if (c.width <= 0 || c.height <= 0)
                        continue;

                    SpriteLut lut = new SpriteLut();

                    int cy = font.flipTextureY?c.y:(fontInfo.scaleH - c.y - c.height);
                    Texture2D dest = ProcessTexture(gen, false, false,
                        font.texture, c.x, cy, c.width, c.height,
                        ref lut, GetPadAmount(gen, -1));
                    if (dest == null)
                    {
                        // probably fully transparent
                        continue;
                    }

                    lut.sourceTex = dest;
                    lut.tex = dest;
                    lut.source = -1;
                    lut.isFont = true;
                    lut.isDuplicate = false;
                    lut.fontId = i;
                    lut.charId = c.id;
                    lut.rx = lut.rx - c.x;
                    lut.ry = lut.ry - cy;

                    lut.atlasIndex = numTexturesToAtlas++;

                    spriteLuts.Add(lut);
                }

                // Add one blank char for fallbacks
                {
                    int dims = 5;
                    SpriteLut lut = new SpriteLut();
                    lut.tex = new Texture2D(dims, dims);
                    for (int y = 0; y < dims; ++y)
                        for (int x = 0; x < dims; ++x)
                            lut.tex.SetPixel(x, y, Color.clear);
                    lut.tex.Apply();
                    lut.sourceTex = lut.tex;
                    lut.isFont = true;
                    lut.isDuplicate = false;
                    lut.fontId = i;
                    lut.charId = -1;
                    lut.atlasIndex = numTexturesToAtlas++;

                    spriteLuts.Add(lut);
                }
            }
        }

        // Create texture
        Texture2D[] textureList = new Texture2D[numTexturesToAtlas];
        int titer = 0;
        for (int i = 0; i < spriteLuts.Count; ++i)
        {
            SpriteLut _lut = spriteLuts[i];
            if (!_lut.isDuplicate)
            {
                textureList[titer++] = _lut.tex;
            }
        }

        // Build atlas
        tk2dEditor.Atlas.Builder atlasBuilder = new tk2dEditor.Atlas.Builder(gen.maxTextureSize, gen.maxTextureSize, gen.allowMultipleAtlases?64:1, gen.forceSquareAtlas);
        if (textureList.Length > 0)
        {
            foreach (Texture2D currTexture in textureList)
            {
                atlasBuilder.AddRect(currTexture.width, currTexture.height);
            }
            if (atlasBuilder.Build() != 0)
            {
                if (atlasBuilder.HasOversizeTextures())
                {
                    EditorUtility.DisplayDialog("Unable to fit in atlas",
                                                "You have a texture which exceeds the atlas size." +
                                                "Consider putting it in a separate atlas, enabling dicing, or" +
                                                "reducing the texture size",
                                                "Ok");
                }
                else
                {
                    EditorUtility.DisplayDialog("Unable to fit textures in requested atlas area",
                                                "There are too many textures in this collection for the requested " +
                                                "atlas size.",
                                                "Ok");
                }
                return false;
            }
        }

        // Fill atlas textures
        tk2dEditor.Atlas.Data[] atlasData = atlasBuilder.GetAtlasData();
        System.Array.Resize(ref gen.atlasTextures, atlasData.Length);
        System.Array.Resize(ref gen.atlasMaterials, atlasData.Length);
        for (int atlasIndex = 0; atlasIndex < atlasData.Length; ++atlasIndex)
        {
            Texture2D tex = new Texture2D(64, 64, TextureFormat.ARGB32, false);

            gen.atlasWastage = (1.0f - atlasData[0].occupancy) * 100.0f;
            gen.atlasWidth = atlasData[0].width;
            gen.atlasHeight = atlasData[0].height;

            tex.Resize(atlasData[atlasIndex].width, atlasData[atlasIndex].height);

            // Clear texture, unsure if this is REALLY necessary
            // Turns out it is
            for (int yy = 0; yy < tex.height; ++yy)
            {
                for (int xx = 0; xx < tex.width; ++xx)
                {
                    tex.SetPixel(xx, yy, Color.clear);
                }
            }

            for (int i = 0; i < atlasData[atlasIndex].entries.Length; ++i)
            {
                var entry = atlasData[atlasIndex].entries[i];
                Texture2D source = textureList[entry.index];

                if (!entry.flipped)
                {
                    for (int y = 0; y < source.height; ++y)
                    {
                        for (int x = 0; x < source.width; ++x)
                        {
                            tex.SetPixel(entry.x + x, entry.y + y, source.GetPixel(x, y));
                        }
                    }
                }
                else
                {
                    for (int y = 0; y < source.height; ++y)
                    {
                        for (int x = 0; x < source.width; ++x)
                        {
                            tex.SetPixel(entry.x + y, entry.y + x, source.GetPixel(x, y));
                        }
                    }
                }
            }
            tex.Apply();

            string texturePath = gen.atlasTextures[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasTextures[atlasIndex]):(dataDirName + "atlas" + atlasIndex + ".png");

            // Write filled atlas to disk
            byte[] bytes = tex.EncodeToPNG();
            System.IO.FileStream fs = System.IO.File.Create(texturePath);
            fs.Write(bytes, 0, bytes.Length);
            fs.Close();

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            Object.DestroyImmediate(tex);

            tex = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D;
            gen.atlasTextures[atlasIndex] = tex;

            // Make sure texture is set up with the correct max size and compression type
            SetUpTargetTexture(gen, tex);

            // Create material if necessary
            if (gen.atlasMaterials[atlasIndex] == null)
            {
                Material mat;
                if (gen.premultipliedAlpha)
                    mat = new Material(Shader.Find("tk2d/PremulVertexColor"));
                else
                    mat = new Material(Shader.Find("tk2d/BlendVertexColor"));

                mat.mainTexture = tex;

                string materialPath = gen.atlasMaterials[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasMaterials[atlasIndex]):(dataDirName + "atlas" + atlasIndex + "_material.mat");
                AssetDatabase.CreateAsset(mat, materialPath);
                AssetDatabase.SaveAssets();

                gen.atlasMaterials[atlasIndex] = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material;
            }
        }

        // Create prefab
        if (gen.spriteCollection == null)
        {
            GameObject go = new GameObject();
            go.AddComponent<tk2dSpriteCollectionData>();
        #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_4)
            Object p = EditorUtility.CreateEmptyPrefab(prefabObjectPath);
            EditorUtility.ReplacePrefab(go, p);
        #else
            Object p = PrefabUtility.CreateEmptyPrefab(prefabObjectPath);
            PrefabUtility.ReplacePrefab(go, p);
        #endif
            GameObject.DestroyImmediate(go);
            AssetDatabase.SaveAssets();

            gen.spriteCollection = AssetDatabase.LoadAssetAtPath(prefabObjectPath, typeof(tk2dSpriteCollectionData)) as tk2dSpriteCollectionData;
        }

        tk2dSpriteCollectionData coll = gen.spriteCollection;
        coll.textures = new Texture[gen.atlasTextures.Length];
        coll.materials = new Material[gen.atlasMaterials.Length];
        for (int i = 0; i < gen.atlasTextures.Length; ++i)
        {
            coll.textures[i] = gen.atlasTextures[i];
        }
        for (int i = 0; i < gen.atlasMaterials.Length; ++i)
        {
            coll.materials[i] = gen.atlasMaterials[i];
        }

        // Wipe out legacy data
        coll.material = null;

        coll.premultipliedAlpha = gen.premultipliedAlpha;
        coll.spriteDefinitions = new tk2dSpriteDefinition[gen.textureParams.Length];
        coll.version = tk2dSpriteCollectionData.CURRENT_VERSION;
        coll.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen));
        coll.spriteCollectionName = gen.name;
        coll.invOrthoSize = 1.0f / gen.targetOrthoSize;
        coll.halfTargetHeight = gen.targetHeight * 0.5f;

        int buildKey = Random.Range(0, int.MaxValue);
        while (buildKey == coll.buildKey)
        {
            buildKey = Random.Range(0, int.MaxValue);
        }
        coll.buildKey = buildKey; // a random build number so we can identify changed collections quickly

        for (int i = 0; i < coll.spriteDefinitions.Length; ++i)
        {
            coll.spriteDefinitions[i] = new tk2dSpriteDefinition();
            if (gen.textureRefs[i])
            {
                string assetPath = AssetDatabase.GetAssetPath(gen.textureRefs[i]);
                string guid = AssetDatabase.AssetPathToGUID(assetPath);
                coll.spriteDefinitions[i].sourceTextureGUID = guid;
            }
            else
            {
                coll.spriteDefinitions[i].sourceTextureGUID = "";
            }

            coll.spriteDefinitions[i].extractRegion = gen.textureParams[i].extractRegion;
            coll.spriteDefinitions[i].regionX = gen.textureParams[i].regionX;
            coll.spriteDefinitions[i].regionY = gen.textureParams[i].regionY;
            coll.spriteDefinitions[i].regionW = gen.textureParams[i].regionW;
            coll.spriteDefinitions[i].regionH = gen.textureParams[i].regionH;
        }
        coll.allowMultipleAtlases = gen.allowMultipleAtlases;
        coll.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(coll));

        float scale = 1.0f;
        if (gen.useTk2dCamera)
        {
            scale = 1.0f;
        }
        else
        {
            scale = 2.0f * gen.targetOrthoSize / gen.targetHeight;
        }

        // Build fonts
        foreach (var font in fontInfoDict.Keys)
        {
            var fontInfo = fontInfoDict[font];
            List<SpriteLut> fontSpriteLut = new List<SpriteLut>();
            int fontId = 0;
            for (fontId = 0; fontId < gen.fonts.Length; ++fontId)
                if (gen.fonts[fontId] == font) break;
            foreach (var v in spriteLuts)
            {
                if (v.isFont && v.fontId == fontId)
                    fontSpriteLut.Add(v);
            }

            fontInfo.scaleW = coll.textures[0].width;
            fontInfo.scaleH = coll.textures[0].height;

            // Build a local sprite lut only relevant to this font
            UpdateFontData(gen, scale, atlasData, fontSpriteLut, font, fontInfo);

            // Set material
            font.data.material = coll.materials[0];
            font.editorData.material = coll.materials[0];

            // Mark to save
            EditorUtility.SetDirty(font.data);
        }

        // Build textures
        UpdateVertexCache(gen, scale, atlasData, coll, spriteLuts);

        // Free tmp textures
        foreach (var sprite in spriteLuts)
        {
            if (!sprite.isDuplicate)
                Object.DestroyImmediate(sprite.tex);
        }
        foreach (var tex in allocatedTextures)
            Object.DestroyImmediate(tex);

        // refresh existing
        RefreshExistingAssets(gen.spriteCollection);

        // save changes
        var index = tk2dEditorUtility.GetOrCreateIndex();
        index.AddSpriteCollectionData(gen.spriteCollection);
        EditorUtility.SetDirty(gen.spriteCollection);
        EditorUtility.SetDirty(gen);

        sourceTextures = null; // need to clear, its static
        currentBuild = null;

        tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection);
        tk2dEditorUtility.CommitIndex();

        Object.DestroyImmediate(blankTexture);

        return true;
    }
    static Texture2D ProcessTexture(tk2dSpriteCollection settings, bool additive, bool stretchPad, Texture2D srcTex, int sx, int sy, int tw, int th, ref SpriteLut spriteLut, int padAmount)
    {
        // Can't have additive without premultiplied alpha
        if (!settings.premultipliedAlpha) additive = false;
        bool allowTrimming = !settings.disableTrimming;
        var textureCompression = settings.textureCompression;

        int[] ww = new int[tw];
        int[] hh = new int[th];
        for (int x = 0; x < tw; ++x) ww[x] = 0;
        for (int y = 0; y < th; ++y) hh[y] = 0;
        int numNotTransparent = 0;
        for (int x = 0; x < tw; ++x)
        {
            for (int y = 0; y < th; ++y)
            {
                Color col = srcTex.GetPixel(sx + x, sy + y);
                if (col.a > 0)
                {
                    ww[x] = 1;
                    hh[y] = 1;
                    numNotTransparent++;
                }
            }
        }

        if (numNotTransparent > 0)
        {
            int x0 = 0, x1 = 0, y0 = 0, y1 = 0;
            for (int x = 0; x < tw; ++x) if (ww[x] == 1) { x0 = x; break; }
            for (int x = tw - 1; x >= 0; --x) if (ww[x] == 1) { x1 = x; break; }
            for (int y = 0; y < th; ++y) if (hh[y] == 1) { y0 = y; break; }
            for (int y = th - 1; y >= 0; --y) if (hh[y] == 1) { y1 = y; break; }

            int w1 = x1 - x0 + 1;
            int h1 = y1 - y0 + 1;

            if (!allowTrimming)
            {
                x0 = 0;
                y0 = 0;
                w1 = tw;
                h1 = th;
            }

            Texture2D dtex = new Texture2D(w1 + padAmount * 2, h1 + padAmount * 2);
            for (int x = 0; x < w1; ++x)
            {
                for (int y = 0; y < h1; ++y)
                {
                    Color col = srcTex.GetPixel(sx + x0 + x, sy + y0 + y);
                    dtex.SetPixel(x + padAmount, y + padAmount, col);
                }
            }

            if (settings.premultipliedAlpha)
            {
                for (int x = 0; x < dtex.width; ++x)
                {
                    for (int y = 0; y < dtex.height; ++y)
                    {
                        Color col = dtex.GetPixel(x, y);
                        col.r *= col.a; col.g *= col.a; col.b *= col.a;
                        col.a = additive?0.0f:col.a;
                        dtex.SetPixel(x, y, col);
                    }
                }
            }

            PadTexture(dtex, padAmount, stretchPad);
            switch (textureCompression)
            {
            case tk2dSpriteCollection.TextureCompression.Dithered16Bit_4444:
                tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.ARGB4444, 0, 0, dtex.width, dtex.height); break;
            case tk2dSpriteCollection.TextureCompression.Dithered16Bit_565:
                tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.RGB565, 0, 0, dtex.width, dtex.height); break;
            }
            dtex.Apply();

            spriteLut.rx = sx + x0;
            spriteLut.ry = sy + y0;
            spriteLut.rw = w1;
            spriteLut.rh = h1;
            spriteLut.tex = dtex;

            return dtex;
        }
        else
        {
            return null;
        }
    }
    static int GetPadAmount(tk2dSpriteCollection gen, int spriteId)
    {
        int basePadAmount = 0;

        if (gen.padAmount == -1) basePadAmount = (gen.filterMode == FilterMode.Point)?0:defaultPad;
        else basePadAmount = gen.padAmount;

        if (spriteId >= 0)
            basePadAmount += (gen.textureParams[spriteId].extraPadding==-1)?0:gen.textureParams[spriteId].extraPadding;

        return Mathf.Max(0, basePadAmount);
    }
    static void SetUpTargetTexture(tk2dSpriteCollection gen, Texture2D tex)
    {
        bool textureDirty = false;

        string targetTexPath = AssetDatabase.GetAssetPath(tex);
        TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(targetTexPath);
        if (gen.maxTextureSize != importer.maxTextureSize)
        {
            importer.maxTextureSize = gen.maxTextureSize;
            textureDirty = true;
        }
        TextureImporterFormat targetFormat;
        switch (gen.textureCompression)
        {
        case tk2dSpriteCollection.TextureCompression.Uncompressed: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;
        case tk2dSpriteCollection.TextureCompression.Reduced16Bit: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Dithered16Bit_4444: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Dithered16Bit_565: targetFormat = TextureImporterFormat.Automatic16bit; break;
        case tk2dSpriteCollection.TextureCompression.Compressed: targetFormat = TextureImporterFormat.AutomaticCompressed; break;

        default: targetFormat = TextureImporterFormat.AutomaticTruecolor; break;
        }

        if (targetFormat != importer.textureFormat)
        {
            importer.textureFormat = targetFormat;
            textureDirty = true;
        }

        // Make sure texture is set to point filtered when no pad mode is selected
        FilterMode targetFilterMode = gen.pixelPerfectPointSampled?FilterMode.Point:FilterMode.Bilinear;
        if (tex.filterMode != targetFilterMode)
        {
            importer.filterMode = targetFilterMode;
            EditorUtility.SetDirty(importer);
            textureDirty = true;
        }

        if (textureDirty)
        {
            EditorUtility.SetDirty(importer);
            AssetDatabase.ImportAsset(targetTexPath);
        }
    }
    static Texture2D ProcessTexture(tk2dSpriteCollection settings, bool additive, bool stretchPad, bool disableTrimming, bool isInjectedTexture, Texture2D srcTex, int sx, int sy, int tw, int th, ref SpriteLut spriteLut, int padAmount)
    {
        // Can't have additive without premultiplied alpha
        if (!settings.premultipliedAlpha) additive = false;
        bool allowTrimming = !settings.disableTrimming && !disableTrimming;
        var textureCompression = settings.textureCompression;

        int[] ww = new int[tw];
        int[] hh = new int[th];
        for (int x = 0; x < tw; ++x) ww[x] = 0;
        for (int y = 0; y < th; ++y) hh[y] = 0;
        int numNotTransparent = 0;
        for (int x = 0; x < tw; ++x)
        {
            for (int y = 0; y < th; ++y)
            {
                Color col = srcTex.GetPixel(sx + x, sy + y);
                if (col.a > 0)
                {
                    ww[x] = 1;
                    hh[y] = 1;
                    numNotTransparent++;
                }
            }
        }

        if (numNotTransparent > 0)
        {
            int x0 = 0, x1 = 0, y0 = 0, y1 = 0;

            bool customSpriteGeometry = false;
            if (!isInjectedTexture && settings.textureParams[spriteLut.source].customSpriteGeometry) customSpriteGeometry = true;

            // For custom geometry, use the bounds of the geometry
            if (customSpriteGeometry)
            {
                var textureParams = settings.textureParams[spriteLut.source];

                x0 = int.MaxValue;
                y0 = int.MaxValue;
                x1 = -1;
                y1 = -1;

                foreach (var island in textureParams.geometryIslands)
                {
                    foreach (var vert in island.points)
                    {
                        int minX = Mathf.FloorToInt(vert.x);
                        int maxX = Mathf.CeilToInt(vert.x);
                        float y = th - 1 - vert.y;
                        int minY = Mathf.FloorToInt(y);
                        int maxY = Mathf.CeilToInt(y);

                        x0 = Mathf.Min(x0, minX);
                        y0 = Mathf.Min(y0, minY);
                        x1 = Mathf.Max(x1, maxX);
                        y1 = Mathf.Max(y1, maxY);
                    }
                }
            }
            else
            {
                for (int x = 0; x < tw; ++x) if (ww[x] == 1) { x0 = x; break; }
                for (int x = tw - 1; x >= 0; --x) if (ww[x] == 1) { x1 = x; break; }
                for (int y = 0; y < th; ++y) if (hh[y] == 1) { y0 = y; break; }
                for (int y = th - 1; y >= 0; --y) if (hh[y] == 1) { y1 = y; break; }
            }

            x1 = Mathf.Min(x1, tw - 1);
            y1 = Mathf.Min(y1, th - 1);

            int w1 = x1 - x0 + 1;
            int h1 = y1 - y0 + 1;

            if (!allowTrimming)
            {
                x0 = 0;
                y0 = 0;
                w1 = tw;
                h1 = th;
            }

            Texture2D dtex = new Texture2D(w1 + padAmount * 2, h1 + padAmount * 2);
            for (int x = 0; x < w1; ++x)
            {
                for (int y = 0; y < h1; ++y)
                {
                    Color col = srcTex.GetPixel(sx + x0 + x, sy + y0 + y);
                    dtex.SetPixel(x + padAmount, y + padAmount, col);
                }
            }

            if (settings.premultipliedAlpha)
            {
                for (int x = 0; x < dtex.width; ++x)
                {
                    for (int y = 0; y < dtex.height; ++y)
                    {
                        Color col = dtex.GetPixel(x, y);
                        col.r *= col.a; col.g *= col.a; col.b *= col.a;
                        col.a = additive?0.0f:col.a;
                        dtex.SetPixel(x, y, col);
                    }
                }
            }

            PadTexture(dtex, padAmount, stretchPad);
            switch (textureCompression)
            {
            case tk2dSpriteCollection.TextureCompression.Dithered16Bit_NoAlpha:
                tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.ARGB4444, 0, 0, dtex.width, dtex.height); break;
            case tk2dSpriteCollection.TextureCompression.Dithered16Bit_Alpha:
                tk2dEditor.TextureProcessing.FloydSteinbergDithering.DitherTexture(dtex, TextureFormat.RGB565, 0, 0, dtex.width, dtex.height); break;
            }
            dtex.Apply();

            spriteLut.rx = sx + x0;
            spriteLut.ry = sy + y0;
            spriteLut.rw = w1;
            spriteLut.rh = h1;
            spriteLut.tex = dtex;

            return dtex;
        }
        else
        {
            return null;
        }
    }
	public void SetGeneratorAndSelectedSprite(tk2dSpriteCollection spriteCollection, int selectedSprite)
	{
		searchFilter = "";
		SetGenerator(spriteCollection);
		foreach (var entry in entries)
		{
			if (entry.type == SpriteCollectionEditorEntry.Type.Sprite && entry.index == selectedSprite)
			{
				entry.selected = true;
				break;
			}
		}
		UpdateSelection();
	}
    public static bool Rebuild(tk2dSpriteCollection gen)
    {
        // avoid "recursive" build being triggered by texture watcher
        if (currentBuild != null)
            return false;

        // Version specific checks. These need to be done before the sprite collection is upgraded.
        if (gen.version < 2)
        {
          	if (!tk2dEditor.SpriteCollectionBuilder.Deprecated.CheckAndFixUpParams(gen))
            {
                // Params failed check
                return false;
            }
            tk2dEditor.SpriteCollectionBuilder.Deprecated.SetUpSpriteSheets(gen);
            tk2dEditor.SpriteCollectionBuilder.Deprecated.TrimTextureList(gen);
        }
        currentBuild = gen;
        gen.Upgrade(); // upgrade if necessary. could be invoked by texture watcher.

        // Get some sensible paths to work with
        string dataDirName = GetOrCreateDataPath(gen) + "/";

        string prefabObjectPath = "";
        if (gen.spriteCollection)
            prefabObjectPath = AssetDatabase.GetAssetPath(gen.spriteCollection);
        else
            prefabObjectPath = dataDirName + gen.name + ".prefab";
        BuildDirectoryToFile(prefabObjectPath);

        // Create prefab object, needed for next stage
        CreateDataObject( gen, prefabObjectPath );

        // Special build for platform specific sprite collection
        if (gen.HasPlatformData)
        {
            // Initialize required sprite collections
            tk2dEditor.SpriteCollectionBuilder.PlatformBuilder.InitializeSpriteCollectionPlatforms(gen, System.IO.Path.GetDirectoryName(prefabObjectPath));

            // The first sprite collection is always THIS
            tk2dAssetPlatform baseAssetPlatform = tk2dSystem.GetAssetPlatform(gen.platforms[0].name);
            float baseScale = (baseAssetPlatform != null)?baseAssetPlatform.scale:1.0f;

            // Building platform specific data, allow recursive builds temporarily
            currentBuild = null;

            // Transfer to platform sprite collections, and build those
            for (int i = 0; i < gen.platforms.Count; ++i)
            {
                tk2dSpriteCollectionPlatform platform = gen.platforms[i];

                tk2dAssetPlatform thisAssetPlatform = tk2dSystem.GetAssetPlatform(gen.platforms[i].name);
                float thisScale = (thisAssetPlatform != null)?thisAssetPlatform.scale:1.0f;

                bool validPlatform = platform.name.Length > 0 && platform.spriteCollection != null;
                bool isRootSpriteCollection = (i == 0);
                if (validPlatform)
                {
                    tk2dSpriteCollection thisPlatformCollection = gen.platforms[i].spriteCollection;

                    // Make sure data directory exists, material overrides will be created in here
                    string dataPath = GetOrCreateDataPath(thisPlatformCollection);

                    tk2dEditor.SpriteCollectionBuilder.PlatformBuilder.UpdatePlatformSpriteCollection(
                        gen, thisPlatformCollection, dataPath, isRootSpriteCollection, thisScale / baseScale, platform.name);
                    Rebuild(thisPlatformCollection);
                }
            }

            // Pull atlas data from default platform
            gen.atlasMaterials = gen.platforms[0].spriteCollection.atlasMaterials;
            gen.altMaterials = gen.platforms[0].spriteCollection.altMaterials;

            // Fill up our sprite collection data
            List<string> platformNames = new List<string>();
            List<string> platformGUIDs = new List<string>();

            for (int i = 0; i < gen.platforms.Count; ++i)
            {
                tk2dSpriteCollectionPlatform platform = gen.platforms[i];
                if (!platform.Valid) continue;

                platformNames.Add(platform.name);
                tk2dSpriteCollectionData data = platform.spriteCollection.spriteCollection;
                string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(data));
                platformGUIDs.Add(guid);

                // Make loadable
                tk2dSystemUtility.MakeLoadableAsset(data, ""); // unnamed loadable object
            }

            // Set up fonts
            for (int j = 0; j < gen.fonts.Length; ++j)
            {
                tk2dSpriteCollectionFont font = gen.fonts[j];
                if (font == null) continue;

                tk2dFontData data = font.data;
                if (!data) continue;
                data.hasPlatformData = true;
                data.material = null;
                data.materialInst = null;
                data.fontPlatforms = platformNames.ToArray();
                data.fontPlatformGUIDs = new string[platformNames.Count];
                for (int i = 0; i < gen.platforms.Count; ++i)
                {
                    tk2dSpriteCollectionPlatform platform = gen.platforms[i];
                    if (!platform.Valid) continue;
                    data.fontPlatformGUIDs[i] = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen.platforms[i].spriteCollection.fonts[j].data));
                }

                EditorUtility.SetDirty(data);
            }

            gen.spriteCollection.version = tk2dSpriteCollectionData.CURRENT_VERSION;
            gen.spriteCollection.spriteCollectionName = gen.name;
            gen.spriteCollection.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen));
            gen.spriteCollection.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen.spriteCollection));

            // Clear out data
            gen.spriteCollection.spriteDefinitions = new tk2dSpriteDefinition[0];
            gen.spriteCollection.materials = new Material[0];
            gen.spriteCollection.textures = new Texture2D[0];

            gen.spriteCollection.hasPlatformData = true;
            gen.spriteCollection.spriteCollectionPlatforms = platformNames.ToArray();
            gen.spriteCollection.spriteCollectionPlatformGUIDs = platformGUIDs.ToArray();

            EditorUtility.SetDirty(gen);
            EditorUtility.SetDirty(gen.spriteCollection);

            // Index this properly
            tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection);
            tk2dEditorUtility.CommitIndex();

            AssetDatabase.SaveAssets();

            ResetCurrentBuild();
            return true;
        }
        else
        {
            // clear platform data
            gen.spriteCollection.ResetPlatformData(); // in case its being used
            gen.spriteCollection.hasPlatformData = false;
            gen.spriteCollection.spriteCollectionPlatforms = new string[0];
            gen.spriteCollection.spriteCollectionPlatformGUIDs = new string[0];

            // Set up fonts
            for (int j = 0; j < gen.fonts.Length; ++j)
            {
                tk2dFontData f = gen.fonts[j].data;
                if (f != null)
                {
                    f.ResetPlatformData();
                    f.hasPlatformData = false;
                    f.fontPlatforms = new string[0];
                    f.fontPlatformGUIDs = new string[0];
                    EditorUtility.SetDirty(f);
                }
            }
        }

        // Make sure all source textures are in the correct format
        SetUpSourceTextureFormats(gen);

        // blank texture used when texture has been deleted
        Texture2D blankTexture = new Texture2D(2, 2);
        blankTexture.SetPixel(0, 0, Color.magenta);
        blankTexture.SetPixel(0, 1, Color.yellow);
        blankTexture.SetPixel(1, 0, Color.cyan);
        blankTexture.SetPixel(1, 1, Color.grey);
        blankTexture.Apply();

        // make local texture sources
        List<Texture2D> allocatedTextures = new List<Texture2D>();
        sourceTextures = new Texture2D[gen.textureParams.Length];
        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            var param = gen.textureParams[i];
            if (param.extractRegion && param.texture != null)
            {
                Texture2D localTex = new Texture2D(param.regionW, param.regionH);
                for (int y = 0; y < param.regionH; ++y)
                {
                    for (int x = 0; x < param.regionW; ++x)
                    {
                        localTex.SetPixel(x, y, param.texture.GetPixel(param.regionX + x, param.regionY + y));
                    }
                }
                localTex.name = param.texture.name + "/" + param.regionId.ToString();
                localTex.Apply();
                allocatedTextures.Add(localTex);
                sourceTextures[i] = localTex;
            }
            else
            {
                sourceTextures[i] = gen.textureParams[i].texture;
            }
        }

        // catalog all textures to atlas
        int numTexturesToAtlas = 0;
        List<SpriteLut> spriteLuts = new List<SpriteLut>();
        for (int i = 0; i < gen.textureParams.Length; ++i)
        {
            Texture2D currentTexture = sourceTextures[i];

            if (sourceTextures[i] == null)
            {
                gen.textureParams[i].dice = false;
                gen.textureParams[i].anchor = tk2dSpriteCollectionDefinition.Anchor.MiddleCenter;
                gen.textureParams[i].name = "";
                gen.textureParams[i].extractRegion = false;
                gen.textureParams[i].fromSpriteSheet = false;

                currentTexture = blankTexture;
            }
            else
            {
                if (gen.textureParams[i].name == null || gen.textureParams[i].name == "")
                {
                    if (gen.textureParams[i].texture != currentTexture && !gen.textureParams[i].fromSpriteSheet)
                    {
                        gen.textureParams[i].name = currentTexture.name;
                    }
                }
            }

            if (gen.textureParams[i].dice)
            {
                // prepare to dice this up
                int diceUnitX = gen.textureParams[i].diceUnitX;
                int diceUnitY = gen.textureParams[i].diceUnitY;
                if (diceUnitX <= 0) diceUnitX = 128; // something sensible, please
                if (diceUnitY <= 0) diceUnitY = diceUnitX; // make square if not set

                Texture2D srcTex = currentTexture;
                for (int sx = 0; sx < srcTex.width; sx += diceUnitX)
                {
                    for (int sy = 0; sy < srcTex.height; sy += diceUnitY)
                    {
                        int tw = Mathf.Min(diceUnitX, srcTex.width - sx);
                        int th = Mathf.Min(diceUnitY, srcTex.height - sy);

                        SpriteLut diceLut = new SpriteLut();
                        diceLut.source = i;
                        diceLut.isSplit = true;
                        diceLut.sourceTex = srcTex;
                        diceLut.isDuplicate = false; // duplicate diced textures can be chopped up differently, so don't detect dupes here

                        Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, true, gen.textureParams[i].disableTrimming, false, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen, i));
                        if (dest)
                        {
                            diceLut.atlasIndex = numTexturesToAtlas++;
                            spriteLuts.Add(diceLut);
                        }
                    }
                }
            }
            else
            {
                SpriteLut lut = new SpriteLut();
                lut.sourceTex = currentTexture;
                lut.source = i;

                lut.isSplit = false;
                lut.isDuplicate = false;
                for (int j = 0; j < spriteLuts.Count; ++j)
                {
                    if (spriteLuts[j].sourceTex == lut.sourceTex)
                    {
                        lut.isDuplicate = true;
                        lut.atlasIndex = spriteLuts[j].atlasIndex;
                        lut.tex = spriteLuts[j].tex; // get old processed tex

                        lut.rx = spriteLuts[j].rx; lut.ry = spriteLuts[j].ry;
                        lut.rw = spriteLuts[j].rw; lut.rh = spriteLuts[j].rh;

                        break;
                    }
                }

                if (!lut.isDuplicate)
                {
                    lut.atlasIndex = numTexturesToAtlas++;
                    bool stretchPad = false;
                    if (gen.textureParams[i].pad == tk2dSpriteCollectionDefinition.Pad.Extend) stretchPad = true;

                    Texture2D dest = ProcessTexture(gen, gen.textureParams[i].additive, stretchPad, gen.textureParams[i].disableTrimming, false, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen, i));
                    if (dest == null)
                    {
                        // fall back to a tiny blank texture
                        lut.tex = new Texture2D(1, 1);
                        lut.tex.SetPixel(0, 0, new Color( 0, 0, 0, 0 ));
                        PadTexture(lut.tex, GetPadAmount(gen, i), stretchPad);
                        lut.tex.Apply();

                        lut.rx = currentTexture.width / 2; lut.ry = currentTexture.height / 2;
                        lut.rw = 1; lut.rh = 1;
                    }
                }

                spriteLuts.Add(lut);
            }
        }

        // Font
        Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info> fontInfoDict = new Dictionary<tk2dSpriteCollectionFont, tk2dEditor.Font.Info>();
        if (gen.fonts != null)
        {
            for (int i = 0; i < gen.fonts.Length; ++i)
            {
                var font = gen.fonts[i];
                if (!font.InUse) continue;

                var fontInfo = tk2dEditor.Font.Builder.ParseBMFont( AssetDatabase.GetAssetPath(font.bmFont) );
                fontInfoDict[font] = fontInfo;
                foreach (var c in fontInfo.chars)
                {
                    // skip empty textures
                    if (c.width <= 0 || c.height <= 0)
                        continue;

                    SpriteLut lut = new SpriteLut();

                    int cy = font.flipTextureY?c.y:(fontInfo.scaleH - c.y - c.height);
                    Texture2D dest = ProcessTexture(gen, false, false, false, true,
                        font.texture, c.x, cy, c.width, c.height,
                        ref lut, GetPadAmount(gen, -1));
                    if (dest == null)
                    {
                        // probably fully transparent
                        continue;
                    }

                    lut.sourceTex = dest;
                    lut.tex = dest;
                    lut.source = -1;
                    lut.isFont = true;
                    lut.isDuplicate = false;
                    lut.fontId = i;
                    lut.charId = c.id;
                    lut.rx = lut.rx - c.x;
                    lut.ry = lut.ry - cy;

                    lut.atlasIndex = numTexturesToAtlas++;

                    spriteLuts.Add(lut);
                }

                // Add one blank char for fallbacks
                {
                    int dims = 5;
                    SpriteLut lut = new SpriteLut();
                    lut.tex = new Texture2D(dims, dims);
                    for (int y = 0; y < dims; ++y)
                        for (int x = 0; x < dims; ++x)
                            lut.tex.SetPixel(x, y, Color.clear);
                    lut.tex.Apply();
                    lut.sourceTex = lut.tex;
                    lut.isFont = true;
                    lut.isDuplicate = false;
                    lut.fontId = i;
                    lut.charId = -1;
                    lut.atlasIndex = numTexturesToAtlas++;

                    spriteLuts.Add(lut);
                }
            }
        }

        // Create texture
        Texture2D[] textureList = new Texture2D[numTexturesToAtlas];
        int titer = 0;
        for (int i = 0; i < spriteLuts.Count; ++i)
        {
            SpriteLut _lut = spriteLuts[i];
            if (!_lut.isDuplicate)
            {
                textureList[titer++] = _lut.tex;
            }
        }

        // Build atlas
        bool forceAtlasSize = gen.forceTextureSize;
        int atlasWidth = forceAtlasSize?gen.forcedTextureWidth:gen.maxTextureSize;
        int atlasHeight = forceAtlasSize?gen.forcedTextureHeight:gen.maxTextureSize;
        bool forceSquareAtlas = forceAtlasSize?false:gen.forceSquareAtlas;
        bool allowFindingOptimalSize = !forceAtlasSize;
        tk2dEditor.Atlas.Builder atlasBuilder = new tk2dEditor.Atlas.Builder(atlasWidth, atlasHeight, gen.allowMultipleAtlases?64:1, allowFindingOptimalSize, forceSquareAtlas);
        if (textureList.Length > 0)
        {
            foreach (Texture2D currTexture in textureList)
            {
                atlasBuilder.AddRect(currTexture.width, currTexture.height);
            }
            if (atlasBuilder.Build() != 0)
            {
                if (atlasBuilder.HasOversizeTextures())
                {
                    EditorUtility.DisplayDialog("Unable to fit in atlas",
                                                "You have a texture which exceeds the atlas size. " +
                                                "Consider putting it in a separate atlas, enabling dicing, or " +
                                                "reducing the texture size",
                                                "Ok");
                }
                else
                {
                    EditorUtility.DisplayDialog("Unable to fit textures in requested atlas area",
                                                "There are too many textures in this collection for the requested " +
                                                "atlas size.",
                                                "Ok");
                }
                return false;
            }
        }

        // Fill atlas textures
        tk2dEditor.Atlas.Data[] atlasData = atlasBuilder.GetAtlasData();
        System.Array.Resize(ref gen.atlasTextures, atlasData.Length);
        System.Array.Resize(ref gen.atlasMaterials, atlasData.Length);
        if (atlasData.Length > 1)
        {
            // wipe out alt materials when atlas spanning is on
            gen.altMaterials = new Material[0];
        }
        for (int atlasIndex = 0; atlasIndex < atlasData.Length; ++atlasIndex)
        {
            Texture2D tex = new Texture2D(64, 64, TextureFormat.ARGB32, false);

            gen.atlasWastage = (1.0f - atlasData[0].occupancy) * 100.0f;
            gen.atlasWidth = atlasData[0].width;
            gen.atlasHeight = atlasData[0].height;

            tex.Resize(atlasData[atlasIndex].width, atlasData[atlasIndex].height);

            // Clear texture, unsure if this is REALLY necessary
            // Turns out it is
            for (int yy = 0; yy < tex.height; ++yy)
            {
                for (int xx = 0; xx < tex.width; ++xx)
                {
                    tex.SetPixel(xx, yy, Color.clear);
                }
            }

            for (int i = 0; i < atlasData[atlasIndex].entries.Length; ++i)
            {
                var entry = atlasData[atlasIndex].entries[i];
                Texture2D source = textureList[entry.index];

                if (!entry.flipped)
                {
                    for (int y = 0; y < source.height; ++y)
                    {
                        for (int x = 0; x < source.width; ++x)
                        {
                            tex.SetPixel(entry.x + x, entry.y + y, source.GetPixel(x, y));
                        }
                    }
                }
                else
                {
                    for (int y = 0; y < source.height; ++y)
                    {
                        for (int x = 0; x < source.width; ++x)
                        {
                            tex.SetPixel(entry.x + y, entry.y + x, source.GetPixel(x, y));
                        }
                    }
                }
            }
            tex.Apply();

            string texturePath = gen.atlasTextures[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasTextures[atlasIndex]):(dataDirName + "atlas" + atlasIndex + ".png");
            BuildDirectoryToFile(texturePath);

            // Write filled atlas to disk
            byte[] bytes = tex.EncodeToPNG();
            System.IO.FileStream fs = System.IO.File.Create(texturePath);
            fs.Write(bytes, 0, bytes.Length);
            fs.Close();

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            Object.DestroyImmediate(tex);

            tex = AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)) as Texture2D;
            gen.atlasTextures[atlasIndex] = tex;

            // Make sure texture is set up with the correct max size and compression type
            SetUpTargetTexture(gen, tex);

            // Create material if necessary
            if (gen.atlasMaterials[atlasIndex] == null)
            {
                Material mat;
                if (gen.premultipliedAlpha)
                    mat = new Material(Shader.Find("tk2d/PremulVertexColor"));
                else
                    mat = new Material(Shader.Find("tk2d/BlendVertexColor"));

                mat.mainTexture = tex;

                string materialPath = gen.atlasMaterials[atlasIndex]?AssetDatabase.GetAssetPath(gen.atlasMaterials[atlasIndex]):(dataDirName + "atlas" + atlasIndex + " material.mat");
                BuildDirectoryToFile(materialPath);

                AssetDatabase.CreateAsset(mat, materialPath);
                AssetDatabase.SaveAssets();

                gen.atlasMaterials[atlasIndex] = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material;
            }

            // gen.altMaterials must either have length 0, or contain at least the material used in the game
            if (!gen.allowMultipleAtlases && (gen.altMaterials == null || gen.altMaterials.Length == 0))
                gen.altMaterials = new Material[1] { gen.atlasMaterials[0] };
        }

        tk2dSpriteCollectionData coll = gen.spriteCollection;
        coll.textures = new Texture[gen.atlasTextures.Length];
        for (int i = 0; i < gen.atlasTextures.Length; ++i)
        {
            coll.textures[i] = gen.atlasTextures[i];
        }

        if (gen.atlasMaterials.Length == 1)
        {
            coll.materials = new Material[gen.altMaterials.Length];
            for (int i = 0; i < gen.altMaterials.Length; ++i)
                coll.materials[i] = gen.altMaterials[i];
        }
        else
        {
            coll.materials = new Material[gen.atlasMaterials.Length];
            for (int i = 0; i < gen.atlasMaterials.Length; ++i)
                coll.materials[i] = gen.atlasMaterials[i];
        }

        // Wipe out legacy data
        coll.material = null;

        coll.premultipliedAlpha = gen.premultipliedAlpha;
        coll.spriteDefinitions = new tk2dSpriteDefinition[gen.textureParams.Length];
        coll.version = tk2dSpriteCollectionData.CURRENT_VERSION;
        coll.materialIdsValid = true;
        coll.spriteCollectionGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gen));
        coll.spriteCollectionName = gen.name;
        coll.invOrthoSize = 1.0f / gen.targetOrthoSize;
        coll.halfTargetHeight = gen.targetHeight * 0.5f;

        int buildKey = Random.Range(0, int.MaxValue);
        while (buildKey == coll.buildKey)
        {
            buildKey = Random.Range(0, int.MaxValue);
        }
        coll.buildKey = buildKey; // a random build number so we can identify changed collections quickly

        for (int i = 0; i < coll.spriteDefinitions.Length; ++i)
        {
            coll.spriteDefinitions[i] = new tk2dSpriteDefinition();
            if (gen.textureParams[i].texture)
            {
                string assetPath = AssetDatabase.GetAssetPath(gen.textureParams[i].texture);
                string guid = AssetDatabase.AssetPathToGUID(assetPath);
                coll.spriteDefinitions[i].sourceTextureGUID = guid;
            }
            else
            {
                coll.spriteDefinitions[i].sourceTextureGUID = "";
            }

            coll.spriteDefinitions[i].extractRegion = gen.textureParams[i].extractRegion;
            coll.spriteDefinitions[i].regionX = gen.textureParams[i].regionX;
            coll.spriteDefinitions[i].regionY = gen.textureParams[i].regionY;
            coll.spriteDefinitions[i].regionW = gen.textureParams[i].regionW;
            coll.spriteDefinitions[i].regionH = gen.textureParams[i].regionH;
        }
        coll.allowMultipleAtlases = gen.allowMultipleAtlases;
        coll.dataGuid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(coll));

        float scale = 1.0f;
        if (gen.useTk2dCamera)
        {
            scale = 1.0f * gen.globalScale;
        }
        else
        {
            scale = (2.0f * gen.targetOrthoSize / gen.targetHeight) * gen.globalScale;
        }

        // Build fonts
        foreach (var font in fontInfoDict.Keys)
        {
            var fontInfo = fontInfoDict[font];
            List<SpriteLut> fontSpriteLut = new List<SpriteLut>();
            int fontId = 0;
            for (fontId = 0; fontId < gen.fonts.Length; ++fontId)
                if (gen.fonts[fontId] == font) break;
            foreach (var v in spriteLuts)
            {
                if (v.isFont && v.fontId == fontId)
                    fontSpriteLut.Add(v);
            }

            fontInfo.scaleW = coll.textures[0].width;
            fontInfo.scaleH = coll.textures[0].height;

            // Set material
            if (font.useGradient && font.gradientTexture != null && font.gradientCount > 0)
            {
                font.editorData.gradientCount = font.gradientCount;
                font.editorData.gradientTexture = font.gradientTexture;
            }
            else
            {
                font.editorData.gradientCount = 1;
                font.editorData.gradientTexture = null;
            }

            // Build a local sprite lut only relevant to this font
            UpdateFontData(gen, scale, atlasData, fontSpriteLut, font, fontInfo);

            if (font.useGradient && font.gradientTexture != null)
            {
                font.data.gradientCount = font.editorData.gradientCount;
                font.data.gradientTexture = font.editorData.gradientTexture;
                font.data.textureGradients = true;
            }
            else
            {
                font.data.gradientCount = 1;
                font.data.gradientTexture = null;
                font.data.textureGradients = false;
            }

            font.data.spriteCollection = gen.spriteCollection;
            font.data.material = coll.materials[font.materialId];
            font.editorData.material = coll.materials[font.materialId];

            font.data.invOrthoSize = coll.invOrthoSize;
            font.data.halfTargetHeight = coll.halfTargetHeight;
            font.data.texelSize = new Vector3(scale, scale, 0.0f);

            // Managed?
            font.data.managedFont = gen.managedSpriteCollection;
            font.data.needMaterialInstance = gen.managedSpriteCollection;

            // Mark to save
            EditorUtility.SetDirty(font.editorData);
            EditorUtility.SetDirty(font.data);

            // Update font
            tk2dEditorUtility.GetOrCreateIndex().AddOrUpdateFont(font.editorData);
            tk2dEditorUtility.CommitIndex();

            // Loadable?
            if (!tk2dSystemUtility.IsLoadableAsset(font.data))
                tk2dSystemUtility.MakeLoadableAsset(font.data, "");
        }

        // Build textures
        UpdateVertexCache(gen, scale, atlasData, coll, spriteLuts);

        // Free tmp textures
        foreach (var sprite in spriteLuts)
        {
            if (!sprite.isDuplicate)
                Object.DestroyImmediate(sprite.tex);
        }
        foreach (var tex in allocatedTextures)
            Object.DestroyImmediate(tex);

        // refresh existing
        RefreshExistingAssets(gen.spriteCollection);

        // save changes
        gen.spriteCollection.assetName = gen.assetName;
        gen.spriteCollection.managedSpriteCollection = gen.managedSpriteCollection;
        gen.spriteCollection.needMaterialInstance = gen.managedSpriteCollection;

        var index = tk2dEditorUtility.GetOrCreateIndex();
        index.AddSpriteCollectionData(gen.spriteCollection);
        EditorUtility.SetDirty(gen.spriteCollection);
        EditorUtility.SetDirty(gen);

        sourceTextures = null; // need to clear, its static
        currentBuild = null;

        tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection);
        tk2dEditorUtility.CommitIndex();

        Object.DestroyImmediate(blankTexture);

        // update resource system
        if (tk2dSystemUtility.IsLoadableAsset(gen.spriteCollection))
        {
            tk2dSystemUtility.UpdateAssetName(gen.spriteCollection, gen.assetName);
        }

        return true;
    }
 public static void ResetCurrentBuild()
 {
     currentBuild = null;
 }
    static bool SetUpSpriteSheets(tk2dSpriteCollection gen)
    {
        // delete textures which aren't in sprite sheets any more
        // and delete textures which are out of range of the spritesheet
        for (int i = 0; i < gen.textureRefs.Length; ++i)
        {
            if (gen.textureParams[i].fromSpriteSheet)
            {
                bool found = false;
                foreach (var ss in gen.spriteSheets)
                {
                    if (gen.textureRefs[i] == ss.texture)
                    {
                        found = true;
                        int numTiles = (ss.numTiles == 0)?(ss.tilesX * ss.tilesY):Mathf.Min(ss.numTiles, ss.tilesX * ss.tilesY);
                        // delete textures which are out of range
                        if (gen.textureParams[i].regionId >= numTiles)
                        {
                            gen.textureRefs[i] = null;
                            gen.textureParams[i].fromSpriteSheet = false;
                            gen.textureParams[i].extractRegion = false;
                            gen.textureParams[i].colliderType = tk2dSpriteCollectionDefinition.ColliderType.None;
                            gen.textureParams[i].boxColliderMin = Vector3.zero;
                            gen.textureParams[i].boxColliderMax = Vector3.zero;
                        }
                    }
                }

                if (!found)
                {
                    gen.textureRefs[i] = null;
                    gen.textureParams[i].fromSpriteSheet = false;
                    gen.textureParams[i].extractRegion = false;
                    gen.textureParams[i].colliderType = tk2dSpriteCollectionDefinition.ColliderType.None;
                    gen.textureParams[i].boxColliderMin = Vector3.zero;
                    gen.textureParams[i].boxColliderMax = Vector3.zero;
                }
            }
        }

        if (gen.spriteSheets == null)
        {
            gen.spriteSheets = new tk2dSpriteSheetSource[0];
        }

        int spriteSheetId = 0;
        for (spriteSheetId = 0; spriteSheetId < gen.spriteSheets.Length; ++spriteSheetId)
        {
            var spriteSheet = gen.spriteSheets[spriteSheetId];

            // New mode sprite sheets have sprites already created
            if (spriteSheet.version > 0)
                continue;

            // Sanity check
            if (spriteSheet.texture == null)
            {
                continue; // deleted, safely ignore this
            }
            if (spriteSheet.tilesX * spriteSheet.tilesY == 0 ||
                (spriteSheet.numTiles != 0 && spriteSheet.numTiles > spriteSheet.tilesX * spriteSheet.tilesY))
            {
                EditorUtility.DisplayDialog("Invalid sprite sheet",
                                            "Sprite sheet '" + spriteSheet.texture.name + "' has an invalid number of tiles",
                                            "Ok");
                return false;
            }
            if ((spriteSheet.texture.width % spriteSheet.tilesX) != 0 || (spriteSheet.texture.height % spriteSheet.tilesY) != 0)
            {
                EditorUtility.DisplayDialog("Invalid sprite sheet",
                                            "Sprite sheet '" + spriteSheet.texture.name + "' doesn't match tile count",
                                            "Ok");
                return false;
            }

            int numTiles = (spriteSheet.numTiles == 0)?(spriteSheet.tilesX * spriteSheet.tilesY):Mathf.Min(spriteSheet.numTiles, spriteSheet.tilesX * spriteSheet.tilesY);
            for (int y = 0; y < spriteSheet.tilesY; ++y)
            {
                for (int x = 0; x < spriteSheet.tilesX; ++x)
                {
                    // limit to number of tiles, if told to
                    int tileIdx = y * spriteSheet.tilesX + x;
                    if (tileIdx >= numTiles)
                        break;

                    bool foundInCollection = false;

                    // find texture in collection
                    int textureIdx = -1;
                    for (int i = 0; i < gen.textureParams.Length; ++i)
                    {
                        if (gen.textureParams[i].fromSpriteSheet
                            && gen.textureParams[i].regionId == tileIdx
                            && gen.textureRefs[i] == spriteSheet.texture)
                        {
                            textureIdx = i;
                            foundInCollection = true;
                            break;
                        }
                    }

                    if (textureIdx == -1)
                    {
                        // find first empty texture slot
                        for (int i = 0; i < gen.textureParams.Length; ++i)
                        {
                            if (gen.textureRefs[i] == null)
                            {
                                textureIdx = i;
                                break;
                            }
                        }
                    }

                    if (textureIdx == -1)
                    {
                        // texture not found, so extend arrays
                        System.Array.Resize(ref gen.textureRefs, gen.textureRefs.Length + 1);
                        System.Array.Resize(ref gen.textureParams, gen.textureParams.Length + 1);
                        textureIdx = gen.textureRefs.Length - 1;
                    }

                    gen.textureRefs[textureIdx] = spriteSheet.texture;
                    var param = new tk2dSpriteCollectionDefinition();
                    param.fromSpriteSheet = true;
                    param.name = spriteSheet.texture.name + "/" + tileIdx;
                    param.regionId = tileIdx;
                    param.regionW = spriteSheet.texture.width / spriteSheet.tilesX;
                    param.regionH = spriteSheet.texture.height / spriteSheet.tilesY;
                    param.regionX = (tileIdx % spriteSheet.tilesX) * param.regionW;
                    param.regionY = (spriteSheet.tilesY - 1 - (tileIdx / spriteSheet.tilesX)) * param.regionH;
                    param.extractRegion = true;
                    param.additive = spriteSheet.additive;

                    param.pad = spriteSheet.pad;
                    param.anchor = (tk2dSpriteCollectionDefinition.Anchor)spriteSheet.anchor;
                    param.scale = (spriteSheet.scale.sqrMagnitude == 0.0f)?Vector3.one:spriteSheet.scale;

                    // Let the user tweak individually
                    if (foundInCollection)
                    {
                        param.colliderType = gen.textureParams[textureIdx].colliderType;
                        param.boxColliderMin = gen.textureParams[textureIdx].boxColliderMin;
                        param.boxColliderMax = gen.textureParams[textureIdx].boxColliderMax;
                        param.polyColliderIslands = gen.textureParams[textureIdx].polyColliderIslands;
                        param.colliderConvex = gen.textureParams[textureIdx].colliderConvex;
                        param.colliderSmoothSphereCollisions = gen.textureParams[textureIdx].colliderSmoothSphereCollisions;
                        param.colliderColor = gen.textureParams[textureIdx].colliderColor;
                    }
                    else
                    {
                        param.colliderType = spriteSheet.colliderType;
                    }

                    gen.textureParams[textureIdx] = param;
                }
            }
        }

        return true;
    }
    // Create the sprite collection data object
    // Its a prefab for historic reasons
    static void CreateDataObject(tk2dSpriteCollection gen, string prefabObjectPath)
    {
        // Create prefab
        if (gen.spriteCollection == null)
        {
            prefabObjectPath = AssetDatabase.GenerateUniqueAssetPath(prefabObjectPath);

            GameObject go = new GameObject();
            go.AddComponent<tk2dSpriteCollectionData>();
        #if (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4)
            Object p = EditorUtility.CreateEmptyPrefab(prefabObjectPath);
            EditorUtility.ReplacePrefab(go, p);
        #else
            Object p = PrefabUtility.CreateEmptyPrefab(prefabObjectPath);
            PrefabUtility.ReplacePrefab(go, p);
        #endif
            GameObject.DestroyImmediate(go);
            AssetDatabase.SaveAssets();

            gen.spriteCollection = AssetDatabase.LoadAssetAtPath(prefabObjectPath, typeof(tk2dSpriteCollectionData)) as tk2dSpriteCollectionData;
        }
    }
    void OnDisable()
    {
        ClearTextureCache();

        _spriteCollection = null;
        tk2dEditorUtility.CollectAndUnloadUnusedAssets();
    }