private void BuildSingleAtlas()
    {
        texList = BuildTextureList(matSpriteMap[numAtlasesBuilt]);

        if (texList == null)
        {
            updateDelegate = UpdateBuildEnd;
            return;
        }
        // Make sure there are textures in the list:
        if (texList.textures.Count < 1)
        {
            Debug.LogWarning("Warning: No textures found for material \"" + texList.material.name + "\".");
            --numAtlasesBuilt;
        }
        else
        {
            BuildAtlas(texList);
        }

        // Now assign the frame info:
        SetFrameInfo((MaterialSpriteList)matSpriteMap[numAtlasesBuilt], texList);

        // Save the atlas path:
        matSpriteMap[numAtlasesBuilt].texPath = texList.texPath;

        texList = null;

        // Try to free some memory:
        System.GC.Collect();
#if !UNITY_IPHONE || (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9)
        Resources.UnloadUnusedAssets();
#endif

        ++numAtlasesBuilt;

        progress = (float)numAtlasesBuilt / (float)matSpriteMap.Count;

        if (numAtlasesBuilt < matSpriteMap.Count)
        {
            // set message one step prior since each step is non-threaded
            // we need to update message for next step prior to starting
            message = "Building atlas for " + matSpriteMap[numAtlasesBuilt].material.name;
        }
        else
        {
            // set message one step prior since each step is non-threaded
            // we need to update message for next step prior to starting
            message        = "Importing generated atlases";
            updateDelegate = UpdateBuildEnd;
        }
    }
    // Assigns all frame-related information to
    // the sprites of an atlas:
    void SetFrameInfo(MaterialSpriteList msMap, AtlasTextureList texList)
    {
        SPRITE_FRAME      frameInfo;
        ISpriteAggregator spAg;
        AutoSpriteBase    spr;

        int index;

        for (int i = 0; i < msMap.sprites.Count; ++i)
        {
            spAg = (ISpriteAggregator)msMap.sprites[i];

            // Assign each frame its UVs:
            for (int j = 0; j < spAg.SpriteFrames.Length; ++j)
            {
                // Validate that a texture has been selected:
                if (spAg.SourceTextures[j] == null)
                {
                    // Set the frame size to zero to flag it
                    // as a "null" frame:
                    spAg.SpriteFrames[j].uvs = new Rect(0, 0, 0, 0);
                    continue;
                }

                index = texList.textures.IndexOf(spAg.SourceTextures[j]);
                if (index < 0)
                {
                    Debug.LogError("Error assigning frame info: frame " + j + " on sprite \"" + ((SpriteRoot)spAg).name + "\" not found in the texture list!");
                    continue;
                }

                frameInfo     = (SPRITE_FRAME)texList.frames[index];
                frameInfo.uvs = texList.uvs[index];
                spAg.SpriteFrames[j].Copy(frameInfo);
            }

            spr = (AutoSpriteBase)spAg;

            // Update our sprite's appearance:
            if (spr.spriteMesh != null)
            {
                if (spr.DefaultFrame != null)
                {
                    spr.SetUVs(spr.DefaultFrame.uvs);
                }
            }

            EditorUtility.SetDirty(spr.gameObject);
        }
    }
    // Finds all textures which are to be part
    // of a given atlas:
    private AtlasTextureList BuildTextureList(MaterialSpriteList msMap)
    {
        ISpriteAggregator spr;
        Texture2D         newTex    = null;
        SPRITE_FRAME      frameInfo = new SPRITE_FRAME(0);
        AtlasTextureList  texList   = new AtlasTextureList();

        texList.material = msMap.material;

        // Get all the textures pointed to by the sprites:
        for (int i = 0; i < msMap.sprites.Count; ++i)
        {
            spr = (ISpriteAggregator)msMap.sprites[i];
            spr.Aggregate(AssetDatabase.GUIDToAssetPath, AssetDatabase.LoadAssetAtPath, AssetDatabase.AssetPathToGUID);                 // Get the sprite ready to give us its textures

            if (spr.SourceTextures.Length <= 0)
            {
                Debug.LogError("Null texture reference detected on sprite \"" + ((Component)spr).name + "\"! Please verify that this was intentional.");
                return(null);
            }

            for (int j = 0; j < spr.SourceTextures.Length; ++j)
            {
                if (spr.SourceTextures[j] != null)
                {
                    // See if the texture is already in our list:
                    if (-1 >= texList.textures.IndexOf(spr.SourceTextures[j]))
                    {
                        VerifyImportSettings(spr.SourceTextures[j]);
                        texList.textures.Add(spr.SourceTextures[j]);
                        ProcessFrame(spr.SourceTextures[j], spr.DoNotTrimImages, ref newTex, ref frameInfo);
                        texList.trimmedTextures.Add(newTex);
                        texList.frames.Add(frameInfo);
                    }
                }
                else
                {
                    Debug.LogError("Null texture reference detected on sprite \"" + ((Component)spr).name + "\"! Please verify that this was intentional.");
#if WARN_ON_NULL_TEXTURE
                    Debug.LogWarning("Null texture reference detected on sprite \"" + ((Component)spr).name + "\"! Please verify that this was intentional.");
#endif
                }
            }
        }

        return(texList);
    }
	// Assigns all frame-related information to
	// the sprites of an atlas:
	void SetFrameInfo(MaterialSpriteList msMap, AtlasTextureList texList)
	{
		SPRITE_FRAME frameInfo;
		ISpriteAggregator spAg;

		int index;

		for (int i = 0; i < msMap.sprites.Count; ++i)
		{
			spAg = msMap.sprites[i];

			// Assign each frame its UVs:
			for (int j = 0; j < spAg.SpriteFrames.Length; ++j)
			{
				// Validate that a texture has been selected:
				if (spAg.SourceTextures[j] == null)
				{
					// Set the frame size to zero to flag it
					// as a "null" frame:
					spAg.SpriteFrames[j].uvs = new Rect(0, 0, 0, 0);
					continue;
				}

				index = texList.textures.IndexOf(spAg.SourceTextures[j]);
				if (index < 0)
				{
					Debug.LogError("Error assigning frame info: frame " + j + " on object \"" + ((Component)spAg).name + "\" not found in the texture list!");
					continue;
				}

				frameInfo = texList.frames[index];
				frameInfo.uvs = texList.uvs[index];
				spAg.SpriteFrames[j].Copy(frameInfo);
			}

			// Update our sprite's appearance:
			if ( !(spAg is AutoSpriteBase && ((AutoSpriteBase)spAg).spriteMesh == null) )
			{
				if (spAg.DefaultFrame != null)
				{
					spAg.SetUVs(spAg.DefaultFrame.uvs);
				}
			}

			EditorUtility.SetDirty((Component)spAg);
		}
	}
	// Builds an atlas from the specified texture list
	void BuildAtlas(AtlasTextureList texList)
	{
		Texture2D atlas;

		atlas = new Texture2D(4, 4);
		atlas.name = texList.material.name;

		//=============================================
		// The following is currently disabled as it 
		// does not seem to work around the Unity bug:
		//=============================================
		// To get around the Unity bug where the max texture size is
		// limited to 1024x1024 when in iPhone mode for newly-created
		// textures, save this texture to disk as an asset and then
		// re-import it with modified import settings to set the max
		// texture size to what we want:
		byte[] bytes;// = atlas.EncodeToPNG();
		string atlasPath = assetPath + "/" + atlas.name + ".png";
//		string projectRelativePath = "Assets/" + atlasFolder + "/" + atlas.name + ".png";
// 
// 		// Write out the atlas file:
// 		using (FileStream fs = File.Create(atlasPath))
// 		{
// 			fs.Write(bytes, 0, bytes.Length);
// 		}
// 
// 		// Make sure the max texture size is set to what we want:
// 		// Get the texture's importer:
// 		TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(projectRelativePath);
// 		if (importer.maxTextureSize < maxAtlasSize || importer.isReadable)
// 		{
// 			// Re-import it with the desired max texture size:
// 			importer.maxTextureSize = maxAtlasSize;
// 			importer.isReadable = true;
// 			AssetDatabase.ImportAsset(projectRelativePath, ImportAssetOptions.ForceSynchronousImport);
// 		}
// 
// 		// Now re-open the texture asset:
// 		atlas = (Texture2D) AssetDatabase.LoadAssetAtPath(projectRelativePath, typeof(Texture2D));

		// Pack the textures to the atlas:
		texList.uvs = atlas.PackTextures(texList.trimmedTextures.ToArray(), padding, maxAtlasSize);

		// Check to see if the texture had to be resized to fit:
		if (texList.uvs[0].width * atlas.width != (texList.trimmedTextures[0]).width ||
		   texList.uvs[0].height * atlas.height != (texList.trimmedTextures[0]).height)
		{
			EditorUtility.DisplayDialog("WARNING: Textures resized!", "WARNING: Not all textures were able to fit on atlas \"" + atlas.name + "\" at their original sizes. These textures were scaled down to fit.  To resolve this, assign some of your sprites to use a different material, or if possible, use a larger maximum texture size.", "Ok");
			Debug.LogWarning("WARNING: Textures were resized to fit onto atlas \"" + atlas.name + "\"!  To resolve this, assign some of your sprites a different material, or if possible, use a larger maximum texture size.");
		}

		// Free our trimmed texture memory:
		for (int i = 0; i < texList.trimmedTextures.Count; ++i)
		{
			// If this isn't stored as an asset, destroy it:
			if (AssetDatabase.GetAssetPath(texList.trimmedTextures[i]).Length < 1)
				DestroyImmediate(texList.trimmedTextures[i]);
			texList.trimmedTextures[i] = null;
		}
		texList.trimmedTextures.Clear();

#if !UNITY_IPHONE || (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9)
		Resources.UnloadUnusedAssets();
#endif

		// See if the texture needs to be made square:
		if (forceSquare && atlas.width != atlas.height)
		{
			int size = Mathf.Max(atlas.width, atlas.height);
			
			// Create a square texture:
			Texture2D tempTex = (Texture2D)Instantiate(atlas);
			tempTex.name = atlas.name;
			tempTex.Resize(size, size, TextureFormat.ARGB32, false);
			
			// Copy the contents:
			tempTex.SetPixels(0, 0, atlas.width, atlas.height, atlas.GetPixels(0), 0);
			tempTex.Apply(false);
			
			// Scale the UVs to account for this:
			for (int j = 0; j < texList.uvs.Length; ++j)
			{
				// See which side we expanded:
				if (atlas.width > atlas.height)
				{
					texList.uvs[j].y = texList.uvs[j].y * 0.5f;
					texList.uvs[j].yMax = texList.uvs[j].y + (texList.uvs[j].height * 0.5f);
				}
				else
				{
					texList.uvs[j].x = texList.uvs[j].x * 0.5f;
					texList.uvs[j].xMax = texList.uvs[j].x + (texList.uvs[j].width * 0.5f);
				}
			}

			if (atlas != tempTex)
				DestroyImmediate(atlas);
			atlas = tempTex;
		}

		// See if we need to trim the atlas to fit its content:
		if (!forceSquare)
		{
			Texture2D tempTex = TrimAtlas(atlas);

			// Scale the UVs to account for this:
			float widthFactor = ((float)atlas.width) / ((float)tempTex.width);
			float heightFactor = ((float)atlas.height) / ((float)tempTex.height);

			for (int j = 0; j < texList.uvs.Length; ++j)
			{
				texList.uvs[j].x *= widthFactor;
				texList.uvs[j].y *= heightFactor;
				texList.uvs[j].width *= widthFactor;
				texList.uvs[j].height *= heightFactor;
			}

			if (atlas != tempTex)
				DestroyImmediate(atlas);
			atlas = tempTex;
		}

		// Save the atlas as an asset:
		bytes = atlas.EncodeToPNG();

		// Write out the atlas file:
		using (FileStream fs = File.Create(atlasPath))
		{
			fs.Write(bytes, 0, bytes.Length);
		}

		// Flag this memory to be freed:
		bytes = null;

		// Save the atlas path:
		texList.texPath = "Assets/" + atlasFolder + "/" + atlas.name + ".png";

		Debug.Log("Finished building atlas \"" + texList.material.name + "\"...");
	}
	// Finds all textures which are to be part
	// of a given atlas:
	AtlasTextureList BuildTextureList(MaterialSpriteList msMap)
	{
		ISpriteAggregator spr;
		Texture2D newTex = null;
		SPRITE_FRAME frameInfo = new SPRITE_FRAME(0);
		AtlasTextureList texList = new AtlasTextureList();
		texList.material = msMap.material;

		// Get all the textures pointed to by the sprites:
		for (int i = 0; i < msMap.sprites.Count; ++i)
		{
			spr = msMap.sprites[i];
			spr.Aggregate(AssetDatabase.GUIDToAssetPath, AssetDatabase.LoadAssetAtPath, AssetDatabase.AssetPathToGUID);	// Get the sprite ready to give us its textures

			for (int j = 0; j < spr.SourceTextures.Length; ++j)
			{
				if (spr.SourceTextures[j] != null)
				{
					// See if the texture is already in our list:
					if (-1 >= texList.textures.IndexOf(spr.SourceTextures[j]))
					{
						VerifyImportSettings(spr.SourceTextures[j]);
						texList.textures.Add(spr.SourceTextures[j]);
						ProcessFrame(spr.SourceTextures[j], spr.DoNotTrimImages, ref newTex, ref frameInfo);
						texList.trimmedTextures.Add(newTex);
						texList.frames.Add(frameInfo);
					}
				}
				else
				{
#if WARN_ON_NULL_TEXTURE
					Debug.LogWarning("Null texture reference detected on sprite \"" + ((Component)spr).name + "\"! Please verify that this was intentional.");
#endif
				}
			}
		}

		return texList;
	}
    // Builds an atlas from the specified texture list
    void BuildAtlas(AtlasTextureList texList)
    {
        Texture2D atlas;

        atlas      = new Texture2D(4, 4);
        atlas.name = texList.material.name;

        //=============================================
        // The following is currently disabled as it
        // does not seem to work around the Unity bug:
        //=============================================
        // To get around the Unity bug where the max texture size is
        // limited to 1024x1024 when in iPhone mode for newly-created
        // textures, save this texture to disk as an asset and then
        // re-import it with modified import settings to set the max
        // texture size to what we want:
        byte[] bytes;        // = atlas.EncodeToPNG();
        string atlasPath = assetPath + "/" + atlas.name + ".png";

//		string projectRelativePath = "Assets/" + atlasFolder + "/" + atlas.name + ".png";
//
//      // Write out the atlas file:
//      using (FileStream fs = File.Create(atlasPath))
//      {
//          fs.Write(bytes, 0, bytes.Length);
//      }
//
//      // Make sure the max texture size is set to what we want:
//      // Get the texture's importer:
//      TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(projectRelativePath);
//      if (importer.maxTextureSize < maxAtlasSize || importer.isReadable)
//      {
//          // Re-import it with the desired max texture size:
//          importer.maxTextureSize = maxAtlasSize;
//          importer.isReadable = true;
//          AssetDatabase.ImportAsset(projectRelativePath, ImportAssetOptions.ForceSynchronousImport);
//      }
//
//      // Now re-open the texture asset:
//      atlas = (Texture2D) AssetDatabase.LoadAssetAtPath(projectRelativePath, typeof(Texture2D));

        // Pack the textures to the atlas:
        texList.uvs = atlas.PackTextures((Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D)), padding, maxAtlasSize);

        // Check to see if the texture had to be resized to fit:
        if (texList.uvs[0].width * atlas.width != ((Texture2D)texList.trimmedTextures[0]).width ||
            texList.uvs[0].height * atlas.height != ((Texture2D)texList.trimmedTextures[0]).height)
        {
            EditorUtility.DisplayDialog("WARNING: Textures resized!", "WARNING: Not all textures were able to fit on atlas \"" + atlas.name + "\" at their original sizes. These textures were scaled down to fit.  To resolve this, assign some of your sprites to use a different material, or if possible, use a larger maximum texture size.", "Ok");
            Debug.LogWarning("WARNING: Textures were resized to fit onto atlas \"" + atlas.name + "\"!  To resolve this, assign some of your sprites a different material, or if possible, use a larger maximum texture size.");
        }

        // Free our trimmed texture memory:
        for (int i = 0; i < texList.trimmedTextures.Count; ++i)
        {
            // If this isn't stored as an asset, destroy it:
            if (AssetDatabase.GetAssetPath((Texture2D)texList.trimmedTextures[i]).Length < 1)
            {
                DestroyImmediate((Texture2D)texList.trimmedTextures[i]);
            }
            texList.trimmedTextures[i] = null;
        }
        texList.trimmedTextures.Clear();

#if !UNITY_IPHONE || (UNITY_3_0 || UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_3_6 || UNITY_3_7 || UNITY_3_8 || UNITY_3_9)
        Resources.UnloadUnusedAssets();
#endif

        // See if the texture needs to be made square:
        if (forceSquare && atlas.width != atlas.height)
        {
            int size = Mathf.Max(atlas.width, atlas.height);

            // Create a square texture:
            Texture2D tempTex = (Texture2D)Instantiate(atlas);
            tempTex.name = atlas.name;
            tempTex.Resize(size, size, TextureFormat.ARGB32, false);

            // Copy the contents:
            tempTex.SetPixels(0, 0, atlas.width, atlas.height, atlas.GetPixels(0), 0);
            tempTex.Apply(false);

            // Scale the UVs to account for this:
            for (int j = 0; j < texList.uvs.Length; ++j)
            {
                // See which side we expanded:
                if (atlas.width > atlas.height)
                {
                    texList.uvs[j].y    = texList.uvs[j].y * 0.5f;
                    texList.uvs[j].yMax = texList.uvs[j].y + (texList.uvs[j].height * 0.5f);
                }
                else
                {
                    texList.uvs[j].x    = texList.uvs[j].x * 0.5f;
                    texList.uvs[j].xMax = texList.uvs[j].x + (texList.uvs[j].width * 0.5f);
                }
            }

            if (atlas != tempTex)
            {
                DestroyImmediate(atlas);
            }
            atlas = tempTex;
        }

        // See if we need to trim the atlas to fit its content:
        if (!forceSquare)
        {
            Texture2D tempTex = TrimAtlas(atlas);

            // Scale the UVs to account for this:
            float widthFactor  = ((float)atlas.width) / ((float)tempTex.width);
            float heightFactor = ((float)atlas.height) / ((float)tempTex.height);

            for (int j = 0; j < texList.uvs.Length; ++j)
            {
                texList.uvs[j].x      *= widthFactor;
                texList.uvs[j].y      *= heightFactor;
                texList.uvs[j].width  *= widthFactor;
                texList.uvs[j].height *= heightFactor;
            }

            if (atlas != tempTex)
            {
                DestroyImmediate(atlas);
            }
            atlas = tempTex;
        }

        // Save the atlas as an asset:
        bytes = atlas.EncodeToPNG();

        // Write out the atlas file:
        using (FileStream fs = File.Create(atlasPath))
        {
            fs.Write(bytes, 0, bytes.Length);
        }

        // Flag this memory to be freed:
        bytes = null;

        // Save the atlas path:
        texList.texPath = "Assets/" + atlasFolder + "/" + atlas.name + ".png";

        Debug.Log("Finished building atlas \"" + texList.material.name + "\"...");
    }
	// Builds an atlas from the specified texture list
	void BuildAtlas(AtlasTextureList texList)
	{
		Texture2D atlas;

		atlas = new Texture2D(32, 32);
		atlas.name = texList.material.name;
		texList.uvs = atlas.PackTextures((Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D)), padding, maxAtlasSize);

		// Check to see if the texture had to be resized to fit:
		if (texList.uvs[0].width * atlas.width != ((Texture2D)texList.trimmedTextures[0]).width ||
		   texList.uvs[0].height * atlas.height != ((Texture2D)texList.trimmedTextures[0]).height)
		{
			EditorUtility.DisplayDialog("WARNING: Textures resized!", "WARNING: Not all textures were able to fit on atlas \"" + atlas.name + "\" at their original sizes. These textures were scaled down to fit.  To resolve this, assign some of your sprites to use a different material, or if possible, use a larger maximum texture size.", "Ok");
			Debug.LogWarning("WARNING: Textures were resized to fit onto atlas \"" + atlas.name + "\"!  To resolve this, assign some of your sprites a different material, or if possible, use a larger maximum texture size.");
		}

		// Free our trimmed texture memory:
		for (int i = 0; i < texList.trimmedTextures.Count; ++i)
		{
			// If this isn't stored as an asset, destroy it:
			if (AssetDatabase.GetAssetPath((Texture2D)texList.trimmedTextures[i]).Length < 1)
				DestroyImmediate((Texture2D)texList.trimmedTextures[i]);
			texList.trimmedTextures[i] = null;
		}
		texList.trimmedTextures.Clear();

#if !UNITY_IPHONE || UNITY_3_0
		Resources.UnloadUnusedAssets();
#endif

		// See if the texture needs to be made square:
		if (forceSquare && atlas.width != atlas.height)
		{
			int size = Mathf.Max(atlas.width, atlas.height);
			
			// Create a square texture:
			Texture2D tempTex = (Texture2D)Instantiate(atlas);
			tempTex.name = atlas.name;
			tempTex.Resize(size, size, TextureFormat.ARGB32, false);
			
			// Copy the contents:
			tempTex.SetPixels(0, 0, atlas.width, atlas.height, atlas.GetPixels(0), 0);
			tempTex.Apply(false);
			
			// Scale the UVs to account for this:
			for (int j = 0; j < texList.uvs.Length; ++j)
			{
				// See which side we expanded:
				if (atlas.width > atlas.height)
				{
					texList.uvs[j].y = texList.uvs[j].y * 0.5f;
					texList.uvs[j].yMax = texList.uvs[j].y + (texList.uvs[j].height * 0.5f);
				}
				else
				{
					texList.uvs[j].x = texList.uvs[j].x * 0.5f;
					texList.uvs[j].xMax = texList.uvs[j].x + (texList.uvs[j].width * 0.5f);
				}
			}

			if (atlas != tempTex)
				DestroyImmediate(atlas);
			atlas = tempTex;
		}

		// See if we need to trim the atlas to fit its content:
		if (!forceSquare)
		{
			Texture2D tempTex = TrimAtlas(atlas);

			// Scale the UVs to account for this:
			float widthFactor = ((float)atlas.width) / ((float)tempTex.width);
			float heightFactor = ((float)atlas.height) / ((float)tempTex.height);

			for (int j = 0; j < texList.uvs.Length; ++j)
			{
				texList.uvs[j].x *= widthFactor;
				texList.uvs[j].y *= heightFactor;
				texList.uvs[j].width *= widthFactor;
				texList.uvs[j].height *= heightFactor;
			}

			if (atlas != tempTex)
				DestroyImmediate(atlas);
			atlas = tempTex;
		}

		// Save the atlas as an asset:
		byte[] bytes = atlas.EncodeToPNG();
		string atlasPath = assetPath + "/" + atlas.name + ".png";

		// Write out the atlas file:
		using (FileStream fs = File.Create(atlasPath))
		{
			fs.Write(bytes, 0, bytes.Length);
		}

		// Flag this memory to be freed:
		bytes = null;

		// Save the atlas path:
		texList.texPath = "Assets/" + atlasFolder + "/" + atlas.name + ".png";

		Debug.Log("Finished building atlas \"" + texList.material.name + "\"...");
	}