public static void Rebuild(tk2dSpriteCollection gen)
    {
        // avoid "recursive" build being triggered by texture watcher
        if (currentBuild == gen)
        {
            return;
        }

        currentBuild = gen;

        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;
        }

        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();
                sourceTextures[i] = localTex;
            }
            else
            {
                sourceTextures[i] = gen.textureRefs[i];
            }
        }

        // catalog all textures to atlas
        int numTexturesToAtlas           = 0;
        List <SCGE.SpriteLut> spriteLuts = new List <SCGE.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 == "" || gen.textureParams[i].texture != currentTexture)
                {
                    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);

                        SCGE.SpriteLut diceLut = new SCGE.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.premultipliedAlpha, gen.textureParams[i].additive, true, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen));
                        if (dest)
                        {
                            diceLut.atlasIndex = numTexturesToAtlas++;
                            spriteLuts.Add(diceLut);
                        }
                    }
                }
            }
            else
            {
                SCGE.SpriteLut lut = new SCGE.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.premultipliedAlpha, gen.textureParams[i].additive, stretchPad, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen));
                    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), stretchPad);
                        lut.tex.Apply();

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

                spriteLuts.Add(lut);
            }
        }

        // Create texture
        Texture2D[] textureList = new Texture2D[numTexturesToAtlas];
        int         titer       = 0;

        for (int i = 0; i < spriteLuts.Count; ++i)
        {
            SCGE.SpriteLut _lut = spriteLuts[i];
            if (!_lut.isDuplicate)
            {
                textureList[titer++] = _lut.tex;
            }
        }

        // Build atlas
        Atlas.AtlasBuilder atlasBuilder = new Atlas.AtlasBuilder(gen.maxTextureSize, gen.maxTextureSize, gen.allowMultipleAtlases?64:1);
        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;
            }
        }

        // Fill atlas textures
        Atlas.AtlasData[] 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
            for (int yy = 0; yy < tex.height; ++yy)
            {
                for (int xx = 0; xx < tex.width; ++xx)
                {
                    tex.SetPixel(xx, yy, Color.black);
                }
            }

            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();
            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)
        {
            Object     p  = EditorUtility.CreateEmptyPrefab(prefabObjectPath);
            GameObject go = new GameObject();
            go.AddComponent <tk2dSpriteCollectionData>();
            EditorUtility.ReplacePrefab(go, p);
            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;
        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;
        UpdateVertexCache(gen, atlasData, coll, spriteLuts);

        // refresh existing
        tk2dSprite[] sprs = Resources.FindObjectsOfTypeAll(typeof(tk2dSprite)) as tk2dSprite[];
        foreach (tk2dSprite spr in sprs)
        {
            if (spr.collection == gen.spriteCollection)
            {
                if (spr.spriteId < 0 || spr.spriteId >= spr.collection.spriteDefinitions.Length)
                {
                    spr.spriteId = 0;
                }

                spr.Build();
            }
        }
        tk2dStaticSpriteBatcher[] batchedSprs = Resources.FindObjectsOfTypeAll(typeof(tk2dStaticSpriteBatcher)) as tk2dStaticSpriteBatcher[];
        foreach (var spr in batchedSprs)
        {
            if (spr.spriteCollection == gen.spriteCollection)
            {
                spr.Build();
            }
        }

        // save changes
        EditorUtility.SetDirty(gen.spriteCollection);
        EditorUtility.SetDirty(gen);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

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

        tk2dEditorUtility.GetOrCreateIndex().AddSpriteCollectionData(gen.spriteCollection);
        tk2dEditorUtility.CommitIndex();
    }
    public static void Rebuild(tk2dSpriteCollection gen)
    {
        // avoid "recursive" build being triggered by texture watcher
        if (currentBuild == gen)
            return;

        currentBuild = gen;

        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;
        }

        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();
                sourceTextures[i] = localTex;
            }
            else
            {
                sourceTextures[i] = gen.textureRefs[i];
            }
        }

        // catalog all textures to atlas
        int numTexturesToAtlas = 0;
        List<SCGE.SpriteLut> spriteLuts = new List<SCGE.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 == "" || gen.textureParams[i].texture != currentTexture)
                    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);

                        SCGE.SpriteLut diceLut = new SCGE.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.premultipliedAlpha, gen.textureParams[i].additive, true, srcTex, sx, sy, tw, th, ref diceLut, GetPadAmount(gen));
                        if (dest)
                        {
                            diceLut.atlasIndex = numTexturesToAtlas++;
                            spriteLuts.Add(diceLut);
                        }
                    }
                }
            }
            else
            {
                SCGE.SpriteLut lut = new SCGE.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.premultipliedAlpha, gen.textureParams[i].additive, stretchPad, currentTexture, 0, 0, currentTexture.width, currentTexture.height, ref lut, GetPadAmount(gen));
                    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), stretchPad);
                        lut.tex.Apply();

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

                spriteLuts.Add(lut);
            }
        }

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

        // Build atlas
        Atlas.AtlasBuilder atlasBuilder = new Atlas.AtlasBuilder(gen.maxTextureSize, gen.maxTextureSize, gen.allowMultipleAtlases?64:1);
        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;
            }
        }

        // Fill atlas textures
        Atlas.AtlasData[] 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
            for (int yy = 0; yy < tex.height; ++yy)
            {
                for (int xx = 0; xx < tex.width; ++xx)
                {
                    tex.SetPixel(xx, yy, Color.black);
                }
            }

            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();
            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)
        {
            Object p = EditorUtility.CreateEmptyPrefab(prefabObjectPath);
            GameObject go = new GameObject();
            go.AddComponent<tk2dSpriteCollectionData>();
            EditorUtility.ReplacePrefab(go, p);
            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;
        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;
        UpdateVertexCache(gen, atlasData, coll, spriteLuts);

        // refresh existing
        tk2dSprite[] sprs = Resources.FindObjectsOfTypeAll(typeof(tk2dSprite)) as tk2dSprite[];
        foreach (tk2dSprite spr in sprs)
        {
            if (spr.collection == gen.spriteCollection)
            {
                if (spr.spriteId < 0 || spr.spriteId >= spr.collection.spriteDefinitions.Length)
                    spr.spriteId = 0;

                spr.Build();
            }
        }
        tk2dStaticSpriteBatcher[] batchedSprs = Resources.FindObjectsOfTypeAll(typeof(tk2dStaticSpriteBatcher)) as tk2dStaticSpriteBatcher[];
        foreach (var spr in batchedSprs)
        {
            if (spr.spriteCollection == gen.spriteCollection)
            {
                spr.Build();
            }
        }

        // save changes
        EditorUtility.SetDirty(gen.spriteCollection);
        EditorUtility.SetDirty(gen);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

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

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