private void CreateAtlasDataFile()
    {
        StringBuilder stringBuilder = new StringBuilder("{\"frames\": {\n\n");

        int elementCount = elements.Count;

        string[] elementStrings = new string[elementCount];

        for (int e = 0; e < elementCount; e++)
        {
            PRAtlasElement element = elements[e];
            elementStrings[e] = element.GetJSONString();
        }

        stringBuilder.Append(string.Join(",\n", elementStrings));

        stringBuilder.Append("},\n");

        stringBuilder.Append("\"meta\":{\n");

        stringBuilder.Append("\t\"app\": \"Packrat Atlas Generator github.com/MattRix/Packrat\",\n");
        stringBuilder.Append("\t\"version\": \"1.0\",\n");
        stringBuilder.Append("\t\"image\": \"" + link.atlasFilePath + ".png\",\n");
        stringBuilder.Append("\t\"format\": \"RGBA8888\",\n");
        stringBuilder.Append("\t\"size\": {\"w\":" + atlasWidth + ",\"h\":" + atlasHeight + "},\n");
        stringBuilder.Append("\t\"scale\": \"" + link.scale.ToString() + "\"\n");

        stringBuilder.Append("}\n}\n");

        File.WriteAllText(link.atlasFilePath + ".txt", stringBuilder.ToString());
    }
    private void CleanUp()
    {
        Object.DestroyImmediate(atlasTexture);         //we've already written it to a file, so destroy it

        int elementCount = elements.Count;

        for (int e = 0; e < elementCount; e++)
        {
            PRAtlasElement element = elements[e];
            Object.DestroyImmediate(element.texture);
        }

        Resources.UnloadUnusedAssets();
    }
    private IEnumerator <string> CreateAtlasTexture()
    {
        atlasTexture            = new Texture2D(atlasWidth, atlasHeight, TextureFormat.ARGB32, false);
        atlasTexture.filterMode = FilterMode.Bilinear;
        atlasTexture.SetPixels32(new Color32[atlasWidth * atlasHeight]);       //clear it out (using color32 for speed)

        int elementCount = elements.Count;

        for (int e = 0; e < elementCount; e++)
        {
            PRAtlasElement element = elements[e];

            yield return("Packing " + element.name);

            PRRect packedRect = element.packedRect;

            int extrude = element.extrude;

            int outputX      = packedRect.x + extrude;
            int outputY      = packedRect.y + extrude;
            int outputWidth  = packedRect.width - extrude * 2 - element.padding;
            int outputHeight = packedRect.height - extrude * 2 - element.padding;

            if (link.scale == 1.0f)
            {
                Color[] elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, element.sourceTrimWidth, element.sourceTrimHeight, 0);

                atlasTexture.SetPixels(outputX, outputY, outputWidth, outputHeight, elementPixels);
                //atlasTexture.SetPixels(outputX,outputY,outputWidth,outputHeight,elementPixels);

                if (extrude != 0)                //do extruding by pulling pixels from each edge
                {
                    //left
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, 1, element.sourceTrimHeight, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX - (c + 1), outputY, 1, outputHeight, elementPixels);
                    }

                    //right
                    elementPixels = element.texture.GetPixels(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY, 1, element.sourceTrimHeight, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX + outputWidth + c, outputY, 1, outputHeight, elementPixels);
                    }

                    //bottom
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY, element.sourceTrimWidth, 1, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX, outputY - (c + 1), outputWidth, 1, elementPixels);
                    }

                    //top
                    elementPixels = element.texture.GetPixels(element.sourceTrimX, element.sourceTrimY + element.sourceTrimHeight - 1, element.sourceTrimWidth, 1, 0);
                    for (int c = 0; c < extrude; c++)
                    {
                        atlasTexture.SetPixels(outputX, outputY + outputHeight + c, outputWidth, 1, elementPixels);
                    }

                    //bottom left
                    Color[] cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX, element.sourceTrimY), extrude * extrude);
                    atlasTexture.SetPixels(outputX - extrude, outputY - extrude, extrude, extrude, cornerPixels);

                    //top left
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX, element.sourceTrimY + element.sourceTrimHeight - 1), extrude * extrude);
                    atlasTexture.SetPixels(outputX - extrude, outputY + outputHeight, extrude, extrude, cornerPixels);

                    //top right
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY + element.sourceTrimHeight - 1), extrude * extrude);
                    atlasTexture.SetPixels(outputX + outputWidth, outputY + outputHeight, extrude, extrude, cornerPixels);

                    //bottom right
                    cornerPixels = RXArrayUtil.CreateArrayFilledWithItem <Color>(element.texture.GetPixel(element.sourceTrimX + element.sourceTrimWidth - 1, element.sourceTrimY), extrude * extrude);
                    atlasTexture.SetPixels(outputX + outputWidth, outputY - extrude, extrude, extrude, cornerPixels);
                }
            }
            else             //scale isn't 1, so do a bilinear resample of the texture into the atlas
            {
                /*
                 * Texture2D sourceTexture = element.texture;
                 *
                 * float ratioX = (1.0f / (float)element.sourceFullWidth);
                 * float ratioY = (1.0f / (float)element.sourceFullHeight);
                 *
                 * float trimX = ratioX * element.sourceTrimX;
                 * float trimY = ratioY * element.sourceTrimY;
                 */

                Texture2D sourceTexture = element.texture;

                Color[] outputPixels = new Color[outputWidth * outputHeight];

                float sourceRatioX = 1.0f / (float)element.sourceFullWidth;                 //the width of one pixel in uv coords
                float sourceRatioY = 1.0f / (float)element.sourceFullHeight;                //the height of one pixel in uv coords

                float trimPercentX      = sourceRatioX * (float)element.sourceTrimX;
                float trimPercentY      = sourceRatioY * (float)element.sourceTrimY;
                float trimPercentWidth  = sourceRatioX * (float)element.sourceTrimWidth;
                float trimPercentHeight = sourceRatioY * (float)element.sourceTrimHeight;

                trimPercentX += sourceRatioX * 0.5f;
                trimPercentY += sourceRatioY * 0.5f;

                trimPercentWidth  -= sourceRatioX * 1.0f;
                trimPercentHeight -= sourceRatioX * 1.0f;

                float outputRatioX = 1.0f / (float)(outputWidth - 1);
                float outputRatioY = 1.0f / (float)(outputHeight - 1);

                //Debug.Log(string.Format("{0} tpx:{1} tpy:{2} tpw:{3} tph:{4}",element.name,trimPercentX,trimPercentY,trimPercentWidth,trimPercentHeight));

                for (int r = 0; r < outputHeight; r++)
                {
                    for (int c = 0; c < outputWidth; c++)
                    {
                        float colPercent = (float)c * outputRatioX;
                        float rowPercent = (float)r * outputRatioY;

                        outputPixels[r * outputWidth + c] = sourceTexture.GetPixelBilinear(trimPercentX + colPercent * trimPercentWidth, trimPercentY + rowPercent * trimPercentHeight);

//
                        //multi sample with a kernel
//                      float bx = trimPercentX + colPercent*trimPercentWidth;
//						float by = trimPercentY + rowPercent*trimPercentHeight;
//
//						Color outputColor;
//
//						//outputColor = sourceTexture.GetPixelBilinear(baseX, baseY) * 0.7f;
//
//						float sx = sourceRatioX*(1.0f-link.scale);
//						float sy = sourceRatioY*(1.0f-link.scale);
//
//						float dsx = sx*2;
//						float dsy = sy*2;
//
//						float one = 1.0f/64.0f;
//						float three = 3.0f/64.0f;
//						float nine = 9.0f/64.0f;
//
//						//from https://groups.google.com/forum/#!topic/comp.graphics.algorithms/XpcOL2xiKO4
//
//						outputColor = sourceTexture.GetPixelBilinear(bx-dsx, by+dsy) * one;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by+dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by+dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by+dsy) * one;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by+sy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by+sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by+sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by+sy) * three;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by-sy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by-sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by-sy) * nine;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by-sy) * three;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx-dsx, by-dsy) * one;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sx, by-dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sx, by-dsy) * three;
//						outputColor += sourceTexture.GetPixelBilinear(bx+dsx, by-dsy) * one;

//						outputColor = sourceTexture.GetPixelBilinear(bx, by) * 0.7f;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx, by+sourceRatioY) * 0.05f;
//						outputColor += sourceTexture.GetPixelBilinear(bx, by-sourceRatioY) * 0.05f;
//
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by+sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx+sourceRatioX, by-sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by+sourceRatioY) * 0.0025f;
//						outputColor += sourceTexture.GetPixelBilinear(bx-sourceRatioX, by-sourceRatioY) * 0.0025f;
//
//						outputPixels[r*outputWidth + c] = outputColor;

                        //nearest neighbor
//						int pixelX = Mathf.RoundToInt((trimPercentX + colPercent*trimPercentWidth) * (float)sourceTexture.width);
//						int pixelY = Mathf.RoundToInt((trimPercentY + rowPercent*trimPercentHeight) * (float)sourceTexture.height);
//						outputPixels[r*outputWidth + c] = sourceTexture.GetPixel(pixelX,pixelY);
                    }
                }

                atlasTexture.SetPixels(outputX, outputY, outputWidth, outputHeight, outputPixels);

                if (element.extrude != 0)
                {
                    //yield return "Extruding " + element.name;

                    int heightExtruded = outputHeight + extrude * 2;

                    Color[] sidePixels = new Color[extrude * heightExtruded];                   //used for the left and right sides

                    //LEFT SIDE
                    for (int r = 0; r < heightExtruded; r++)                  //figure out row colour and then fill that row
                    {
                        int   outputRow = Mathf.Max(0, Mathf.Min(outputHeight - 1, r - extrude));
                        Color color     = outputPixels[outputRow * outputWidth];
                        for (int c = 0; c < extrude; c++)
                        {
                            sidePixels[r * extrude + c] = color;
                        }
                        atlasTexture.SetPixels(outputX - extrude, outputY - extrude, extrude, heightExtruded, sidePixels);
                    }

                    //RIGHT SIDE
                    for (int r = 0; r < heightExtruded; r++)                  //figure out row colour and then fill that row
                    {
                        int   outputRow = Mathf.Max(0, Mathf.Min(outputHeight - 1, r - extrude));
                        Color color     = outputPixels[outputRow * outputWidth + outputWidth - 1];
                        for (int c = 0; c < extrude; c++)
                        {
                            sidePixels[r * extrude + c] = color;
                        }
                        atlasTexture.SetPixels(outputX + outputWidth, outputY - extrude, extrude, heightExtruded, sidePixels);
                    }

                    sidePixels = new Color[extrude * outputWidth];                   //used for the top and bottom sides

                    //BOTTOM SIDE
                    for (int c = 0; c < outputWidth; c++)                  //figure out row colour and then fill that row
                    {
                        Color color = outputPixels[c];
                        for (int r = 0; r < extrude; r++)
                        {
                            sidePixels[r * outputWidth + c] = color;
                        }
                        atlasTexture.SetPixels(outputX, outputY - extrude, outputWidth, extrude, sidePixels);
                    }

                    //TOP SIDE
                    int topOffset = (outputHeight - 1) * outputWidth;      //start at the top row
                    for (int c = 0; c < outputWidth; c++)                  //figure out row colour and then fill that row
                    {
                        Color color = outputPixels[topOffset + c];
                        for (int r = 0; r < extrude; r++)
                        {
                            sidePixels[r * outputWidth + c] = color;
                        }
                        atlasTexture.SetPixels(outputX, outputY + outputHeight, outputWidth, extrude, sidePixels);
                    }
                }
            }
        }

//		int count = 5;
//		for(int i = 0; i < count; i++)
//		{
//			float percent = (float)i/(float)(count-1);
//			Debug.Log(i + " percent " + percent);
//		}

        yield return("Writing PNG to disk");

        atlasTexture.Apply(false, false);

        File.WriteAllBytes(link.atlasFilePath + pngSuffix, atlasTexture.EncodeToPNG());

        if (PRViewAtlasWindow.instance != null && PRViewAtlasWindow.instance.link == link)
        {
            PRViewAtlasWindow.instance.UpdateAtlas();
        }

        //in theory this should make it unreadable,
        //but it doesn't matter because we're about to delete it anyway
        //atlasTexture.Apply(false,true);



        //This stuff would be handy, but it's SO SLOW and unreliable that it's not worth it
//		TextureImporter importer = TextureImporter.GetAtPath(link.atlasFilePath+pngSuffix) as TextureImporter;
//
//		if(importer != null)
//		{
//			importer.maxTextureSize = Mathf.Max(importer.maxTextureSize,packedWidth,packedHeight);
//			importer.alphaIsTransparency = true;
//			AssetDatabase.ImportAsset(importer.assetPath);
//		}
//
//		yield return "Importing Atlas";
    }
    private void CalculateElementPacking()
    {
        int elementCount = elements.Count;

        //use the min area of all the elements to start with a sensible estimated size for the atlas to be
        int minArea = 0;

        for (int e = 0; e < elementCount; e++)
        {
            minArea += elements[e].expandedWidth * elements[e].expandedHeight;
        }

        int tryWidth  = 16;
        int tryHeight = 16;

        int tries = 0;

        while ((tryWidth - link.padding) * (tryHeight - link.padding) < minArea && tries++ < 100)
        {
            if (tries % 2 == 0)            //alternate increasing width and height until we find a size that fits everything
            {
                tryWidth *= 2;
            }
            else
            {
                tryHeight *= 2;
            }
        }

        tries = 0;

        //subtract padding because we can't pack right up to the padded border
        //but don't subtract padding*2 because the element sizes already account for padding on one side
        PRPacker packer = new PRPacker(tryWidth - link.padding, tryHeight - link.padding);

        while (tries++ < 100)        //tries is to prevent infinite loops
        {
            bool didFail = false;
            for (int e = 0; e < elementCount; e++)
            {
                PRAtlasElement element = elements[e];

                //Debug.Log("Try fitting " + element.expandedWidth + ", " + element.expandedHeight + " into " + tryWidth+","+tryHeight);
                //TODO update
                PRRect rect = packer.Insert(element.expandedWidth, element.expandedHeight, PRPacker.ChoiceHeuristic.ShortSideFit);

                if (rect.width == 0 && rect.height == 0)                //both at 0 means it failed
                {
                    didFail = true;

                    if (tryWidth <= tryHeight)                    //alternate increasing width and height until we find a size that fits everything
                    {
                        tryWidth *= 2;
                    }
                    else
                    {
                        tryHeight *= 2;
                    }

                    packer.Init(tryWidth - link.padding, tryHeight - link.padding);
                    break;
                }
                else
                {
                    element.packedRect    = rect;
                    element.packedRect.x += element.padding;                     //push the rect off the wall (note, y doesn't need this for the reason below)
                    //flip packing y coord. This is because the algorithm tries to pack everything around 0,0
                    //and we want 0,0 to be top left instead of bottom left (which it would be with Unity's coord system)
                    //there's no real reason for it to be top left, except that it's what people are used to.
                    element.packedRect.y = (tryHeight - element.packedRect.y) - element.packedRect.height;
                }
            }

            if (!didFail)
            {
                atlasWidth  = tryWidth;
                atlasHeight = tryHeight;
                break;                 //we're done!
            }
        }
    }
    private void TrimElements()
    {
        int trimPadding  = link.trimPadding;
        int elementCount = elements.Count;

        for (int e = 0; e < elementCount; e++)
        {
            PRAtlasElement element = elements[e];

            if (element.shouldTrim)
            {
                Color[] sourcePixels = element.texture.GetPixels(0);

                int cols = element.sourceFullWidth;
                //int rows = element.sourceFullHeight;

                int left   = 0;
                int right  = element.sourceFullWidth - 1;
                int top    = element.sourceFullHeight - 1;
                int bottom = 0;

                //note: y=0 is at the bottom, not the top.

                //try to find the first solid pixel on the LEFT
                for (int c = left; c <= right; c++)              //left to right
                {
                    bool didFindSolid = false;

                    for (int r = bottom; r <= top; r++)                  //bottom to top
                    {
                        if (sourcePixels[r * cols + c].a != 0.0f)
                        {
                            didFindSolid = true;
                            left         = c;
                            break;
                        }
                    }

                    if (didFindSolid)
                    {
                        break;
                    }
                }

                //try to find the first solid pixel on the RIGHT
                for (int c = right; c >= left; c--)              //right to left
                {
                    bool didFindSolid = false;

                    for (int r = bottom; r <= top; r++)                  //bottom to top
                    {
                        if (sourcePixels[r * cols + c].a != 0.0f)
                        {
                            didFindSolid = true;
                            right        = c;
                            break;
                        }
                    }

                    if (didFindSolid)
                    {
                        break;
                    }
                }

                //try to find the first solid pixel on the TOP
                for (int r = top; r >= bottom; r--)              //top to bottom
                {
                    bool didFindSolid = false;

                    for (int c = left; c <= right; c++)                  //left to right
                    {
                        if (sourcePixels[r * cols + c].a != 0.0f)
                        {
                            didFindSolid = true;
                            top          = r;
                            break;
                        }
                    }

                    if (didFindSolid)
                    {
                        break;
                    }
                }

                //try to find the first solid pixel on the BOTTOM
                for (int r = bottom; r <= top; r++)              //bottom to top
                {
                    bool didFindSolid = false;

                    for (int c = left; c <= right; c++)                  //left to right
                    {
                        if (sourcePixels[r * cols + c].a != 0.0f)
                        {
                            didFindSolid = true;
                            bottom       = r;
                            break;
                        }
                    }

                    if (didFindSolid)
                    {
                        break;
                    }
                }

                //Debug.Log(element.name + "  left:" + left + " right:"+ right +" top:" + top + " bottom:" + bottom);

                //apply trim padding
                if (trimPadding != 0)
                {
                    left   = Mathf.Max(0, left - trimPadding);
                    right  = Mathf.Min(element.sourceFullWidth - 1, right + trimPadding);
                    bottom = Mathf.Max(0, bottom - trimPadding);
                    top    = Mathf.Min(element.sourceFullHeight - 1, top + trimPadding);
                }

                element.sourceTrimX      = left;
                element.sourceTrimY      = bottom;            //todo: figure out if this should be bottom or top
                element.sourceTrimWidth  = right - left + 1;  //the +1 is because the values are INCLUSIVE
                element.sourceTrimHeight = top - bottom + 1;  //the +1 is because the values are INCLUSIVE
            }
            else
            {
                element.sourceTrimX      = 0;
                element.sourceTrimY      = 0;
                element.sourceTrimWidth  = element.sourceFullWidth;
                element.sourceTrimHeight = element.sourceFullHeight;
            }

            if (element.shouldScale)
            {
                element.scaledTrimX      = Mathf.FloorToInt((float)element.sourceTrimX * link.scale);
                element.scaledTrimY      = Mathf.FloorToInt((float)element.sourceTrimY * link.scale);
                element.scaledTrimWidth  = Mathf.CeilToInt((float)element.sourceTrimWidth * link.scale);
                element.scaledTrimHeight = Mathf.CeilToInt((float)element.sourceTrimHeight * link.scale);
            }
            else
            {
                element.scaledTrimX      = element.sourceTrimX;
                element.scaledTrimY      = element.sourceTrimY;
                element.scaledTrimWidth  = element.sourceTrimWidth;
                element.scaledTrimHeight = element.sourceTrimHeight;
            }

            //padding is only on 2 sides (top and right)
            //extrude is on all 4 sides
            element.expandedWidth  = element.scaledTrimWidth + element.extrude * 2 + element.padding;
            element.expandedHeight = element.scaledTrimHeight + element.extrude * 2 + element.padding;

            //Debug.Log("expanded width " +element.scaledTrimWidth + ", " + element.scaledTrimHeight);

            //Debug.Log("Turned " + element.name + " " + element.sourceFullWidth+","+element.sourceFullHeight + " into " + element.sourceTrimWidth +"," + element.sourceTrimHeight);
            //Debug.Log("Turned " + element.name + " " + element.scaledFullWidth+","+element.scaledFullHeight + " into " + element.scaledTrimWidth +"," + element.scaledTrimHeight);
        }
    }
    private void CreateElementsFromImages()
    {
        SearchOption searchOption = link.shouldAddSubfolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;

        string[] filePaths = Directory.GetFiles(link.sourceFolderPath, "*.png", searchOption);

        elements = new List <PRAtlasElement>(filePaths.Length);

        for (int s = 0; s < filePaths.Length; s++)
        {
            bool shouldAddElement = true;

            string filePath = filePaths[s];

            string fileName = filePath.Remove(0, link.sourceFolderPath.Length + 1);
            fileName = fileName.Remove(fileName.Length - 4, 4); //remove extension
            fileName = fileName.Replace("\\", "/");             //replace slashes

            PRAtlasElement element = new PRAtlasElement(this, fileName);
            element.filePath = filePath;

            Texture2D texture = new Texture2D(0, 0, TextureFormat.ARGB32, false, false);
            texture.wrapMode   = TextureWrapMode.Clamp;           //so we don't get pixels from the other edge when scaling
            texture.filterMode = FilterMode.Trilinear;
            texture.LoadImage(File.ReadAllBytes(filePath));

            if (link.shouldTrim)
            {
                if (element.name.EndsWith("_notrim"))
                {
                    element.shouldTrim = false;
                }
                else
                {
                    element.shouldTrim = true;
                }
            }
            else
            {
                if (element.name.EndsWith("_trim"))
                {
                    element.shouldTrim = true;
                }
                else
                {
                    element.shouldTrim = false;
                }
            }

            if (atlasScaleIndex != -1)
            {
                int elementScaleIndex = GetScaleIndexFromName(element.name);

                if (elementScaleIndex != -1)                  //the element has a scale index
                {
                    if (elementScaleIndex == atlasScaleIndex) //don't scale an element if it has the same suffix
                    {
                        element.shouldScale = false;
                    }
                    else
                    {
                        shouldAddElement = false;                         //this element is for a different scale so don't add it
                    }
                }
            }

            element.padding = link.padding;
            element.extrude = link.extrude;

            element.texture = texture;

            element.sourceFullWidth  = texture.width;
            element.sourceFullHeight = texture.height;

            if (element.shouldScale)
            {
                element.scaledFullWidth  = Mathf.CeilToInt((float)element.sourceFullWidth * link.scale);
                element.scaledFullHeight = Mathf.CeilToInt((float)element.sourceFullHeight * link.scale);
            }
            else
            {
                element.scaledFullWidth  = element.sourceFullWidth;
                element.scaledFullHeight = element.sourceFullHeight;
            }

            if (element.texture == null)
            {
                shouldAddElement = false;
            }

            if (shouldAddElement)
            {
                elements.Add(element);
            }
            else
            {
                if (element.texture != null)
                {
                    UnityEngine.Object.DestroyImmediate(element.texture);
                }
            }
        }
    }
    private void CreateElementsFromImages()
    {
        SearchOption searchOption = link.shouldAddSubfolders ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;

        string[] filePaths = Directory.GetFiles(link.sourceFolderPath,"*.png",searchOption);

        elements = new List<PRAtlasElement>(filePaths.Length);

        for(int s = 0; s<filePaths.Length; s++)
        {
            bool shouldAddElement = true;

            string filePath = filePaths[s];

            string fileName = filePath.Remove(0,link.sourceFolderPath.Length+1);
            fileName = fileName.Remove(fileName.Length-4,4); //remove extension
            fileName = fileName.Replace("\\","/"); //replace slashes

            PRAtlasElement element = new PRAtlasElement(this, fileName);
            element.filePath = filePath;

            Texture2D texture = new Texture2D(0,0,TextureFormat.ARGB32,false,false);
            texture.wrapMode = TextureWrapMode.Clamp; //so we don't get pixels from the other edge when scaling
            texture.filterMode = FilterMode.Trilinear;
            texture.LoadImage(File.ReadAllBytes(filePath));

            if(link.shouldTrim)
            {
                if(element.name.EndsWith("_notrim"))
                {
                    element.shouldTrim = false;
                }
                else
                {
                    element.shouldTrim = true;
                }
            }
            else
            {
                if(element.name.EndsWith("_trim"))
                {
                    element.shouldTrim = true;
                }
                else
                {
                    element.shouldTrim = false;
                }
            }

            if(atlasScaleIndex != -1)
            {
                int elementScaleIndex = GetScaleIndexFromName(element.name);

                if(elementScaleIndex != -1) //the element has a scale index
                {
                    if(elementScaleIndex == atlasScaleIndex) //don't scale an element if it has the same suffix
                    {
                        element.shouldScale = false;
                    }
                    else
                    {
                        shouldAddElement = false; //this element is for a different scale so don't add it
                    }
                }
            }

            element.padding = link.padding;
            element.extrude = link.extrude;

            element.texture = texture;

            element.sourceFullWidth = texture.width;
            element.sourceFullHeight = texture.height;

            if(element.shouldScale)
            {
                element.scaledFullWidth = Mathf.CeilToInt((float)element.sourceFullWidth * link.scale);
                element.scaledFullHeight = Mathf.CeilToInt((float)element.sourceFullHeight * link.scale);
            }
            else
            {
                element.scaledFullWidth = element.sourceFullWidth;
                element.scaledFullHeight = element.sourceFullHeight;
            }

            if(element.texture == null)
            {
                shouldAddElement = false;
            }

            if(shouldAddElement)
            {
                elements.Add(element);
            }
            else
            {
                if(element.texture != null)
                {
                    UnityEngine.Object.DestroyImmediate(element.texture);
                }
            }
        }
    }