bool _combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods){
			bool success = false;
			try{
				_temporaryTextures.Clear();
				
				if (textureEditorMethods != null) textureEditorMethods.Clear();

				if (objsToMesh == null || objsToMesh.Count == 0){
					Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
					return false;
				}
				if (atlasPadding < 0){
					Debug.LogError("Atlas padding must be zero or greater.");
					return false;
				}
				if (maxTilingBakeSize < 2 || maxTilingBakeSize > 4096){
					Debug.LogError("Invalid value for max tiling bake size.");
					return false;			
				}
				
				if (progressInfo != null)
					progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f);
				
				List<string> texPropertyNames = new List<string>();	
				if (!_collectPropertyNames(resultMaterial, texPropertyNames)){
					return false;
				}
				success = __combineTexturesIntoAtlases(progressInfo,resultAtlasesAndRects, resultMaterial, texPropertyNames, objsToMesh,allowedMaterialsFilter, textureEditorMethods);
			} catch (MissingReferenceException mrex){
				Debug.LogError("Creating atlases failed a MissingReferenceException was thrown. This is normally only happens when trying to create very large atlases and Unity is running out of Memory. Try changing the 'Texture Packer' to a different option, it may work with an alternate packer. This error is sometimes intermittant. Try baking again.");
				Debug.LogError(mrex);
			} catch (Exception ex){
				Debug.LogError(ex);
			} finally {
				_destroyTemporaryTextures();
				if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			}
			return success;
		}
		void __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, int _padding, MB2_EditorMethodsInterface textureEditorMethods, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial){
			int numAtlases = texPropertyNames.Count;
			//generate report want to do this before
			//todo if atlas is compressed then doesn't report correct compression 
			StringBuilder report = new StringBuilder();
			if (numAtlases > 0){
				report = new StringBuilder();
				report.AppendLine("Report");
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					MB_TexSet txs = distinctMaterialTextures[i];
					report.AppendLine("----------");
					report.Append("This set of textures will be resized to:" + txs.idealWidth + "x" + txs.idealHeight + "\n");
					for (int j = 0; j < txs.ts.Length; j++){
						if (txs.ts[j].t != null){
							report.Append("   [" + texPropertyNames[j] + " " + txs.ts[j].t.name + " " + txs.ts[j].t.width + "x" + txs.ts[j].t.height + "]");
							if (txs.ts[j].scale != Vector2.one || txs.ts[j].offset != Vector2.zero) report.AppendFormat(" material scale {0} offset{1} ", txs.ts[j].scale.ToString("G4"), txs.ts[j].offset.ToString("G4"));
							if (txs.ts[j].obUVscale != Vector2.one || txs.ts[j].obUVoffset != Vector2.zero) report.AppendFormat(" obUV scale {0} offset{1} ", txs.ts[j].obUVscale.ToString("G4"), txs.ts[j].obUVoffset.ToString("G4"));
							report.AppendLine("");
						} else { 
							report.Append("   [" + texPropertyNames[j] + " null a blank texture will be created]\n");
						}
					}
					report.AppendLine("");
					report.Append("Materials using:");
					for (int j = 0; j < txs.mats.Count; j++){
						report.Append(txs.mats[j].name + ", ");
					}
					report.AppendLine("");
				}
			}		
	
			if (progressInfo != null) progressInfo("Creating txture atlases.", .1f);

			//run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
			GC.Collect();
			Texture2D[] atlases = new Texture2D[numAtlases];			
			Rect[] uvRects;
			if (packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures){
				uvRects = __CreateAtlasesUnityTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, resultMaterial, atlases, textureEditorMethods, _padding);
			} else {
				uvRects = __CreateAtlasesMBTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, resultMaterial, atlases, textureEditorMethods, _padding);
			}
			if (progressInfo != null) progressInfo("Building Report",.7f);
			
			//report on atlases created
			StringBuilder atlasMessage = new StringBuilder();
			atlasMessage.AppendLine("---- Atlases ------");
			for (int i = 0; i < numAtlases; i++){
				if (atlases[i] != null) atlasMessage.AppendLine("Created Atlas For: " + texPropertyNames[i] + " h=" + atlases[i].height + " w=" + atlases[i].width);
			}
			report.Append(atlasMessage.ToString());
			
			
			Dictionary<Material,Rect> mat2rect_map = new Dictionary<Material, Rect>();
			for (int i = 0; i < distinctMaterialTextures.Count; i++){
				List<Material> mats = distinctMaterialTextures[i].mats;
				for (int j = 0; j < mats.Count; j++){
					if (!mat2rect_map.ContainsKey(mats[j])){
						mat2rect_map.Add(mats[j],uvRects[i]);
					}
				}
			}
			
			resultAtlasesAndRects.atlases = atlases;                             // one per texture on source shader
			resultAtlasesAndRects.texPropertyNames = texPropertyNames.ToArray(); // one per texture on source shader
			resultAtlasesAndRects.mat2rect_map = mat2rect_map;
			
			if (progressInfo != null) progressInfo("Restoring Texture Formats & Read Flags",.8f);
			_destroyTemporaryTextures();
			if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			if (report != null && LOG_LEVEL >= MB2_LogLevel.info) Debug.Log(report.ToString());		
		}
		void __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, int _padding, MB2_EditorMethodsInterface textureEditorMethods, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial){
			System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
			sw.Start();
			// note that we may not create some of the atlases because all textures are null
			int numAtlases = texPropertyNames.Count;

			//generate report want to do this before
			//todo if atlas is compressed then doesn't report correct compression 
			StringBuilder report = new StringBuilder();
			if (numAtlases > 0){
				report = new StringBuilder();
				report.AppendLine("Report");
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					MB_TexSet txs = distinctMaterialTextures[i];
					report.AppendLine("----------");
					report.Append("This set of textures will be resized to:" + txs.idealWidth + "x" + txs.idealHeight + "\n");
					for (int j = 0; j < txs.ts.Length; j++){
						if (txs.ts[j].t != null){
							report.Append("   [" + texPropertyNames[j].name + " " + txs.ts[j].t.name + " " + txs.ts[j].t.width + "x" + txs.ts[j].t.height + "]");
							if (txs.ts[j].scale != Vector2.one || txs.ts[j].offset != Vector2.zero) report.AppendFormat(" material scale {0} offset{1} ", txs.ts[j].scale.ToString("G4"), txs.ts[j].offset.ToString("G4"));
							if (txs.ts[j].obUVscale != Vector2.one || txs.ts[j].obUVoffset != Vector2.zero) report.AppendFormat(" obUV scale {0} offset{1} ", txs.ts[j].obUVscale.ToString("G4"), txs.ts[j].obUVoffset.ToString("G4"));
							report.AppendLine("");
						} else { 
							report.Append("   [" + texPropertyNames[j].name + " null ");
							if (allTexturesAreNullAndSameColor[j]){
								report.Append ("no atlas will be created all textures null]\n");
							} else {
								report.AppendFormat("a 16x16 texture will be created with color {0}]\n",txs.ts[j].colorIfNoTexture);
							}
						}
					}
					report.AppendLine("");
					report.Append("Materials using:");
					for (int j = 0; j < txs.mats.Count; j++){
						report.Append(txs.mats[j].name + ", ");
					}
					report.AppendLine("");
				}
			}		
	
			if (progressInfo != null) progressInfo("Creating txture atlases.", .1f);

			//run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
			GC.Collect();
			Texture2D[] atlases = new Texture2D[numAtlases];			
			Rect[] uvRects;
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("time Step 3 Create And Save Atlases part 1 " + sw.ElapsedMilliseconds.ToString("f5") );
			if (_packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures){
				uvRects = __CreateAtlasesUnityTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			} else if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker) {
				uvRects = __CreateAtlasesMBTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			} else {
				uvRects = __CreateAtlasesMBTexturePackerFast(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			}
			float t3 = sw.ElapsedMilliseconds;

			AdjustNonTextureProperties(resultMaterial,texPropertyNames,distinctMaterialTextures,textureEditorMethods);

			if (progressInfo != null) progressInfo("Building Report",.7f);
			
			//report on atlases created
			StringBuilder atlasMessage = new StringBuilder();
			atlasMessage.AppendLine("---- Atlases ------");
			for (int i = 0; i < numAtlases; i++){
				if (atlases[i] != null){
					atlasMessage.AppendLine("Created Atlas For: " + texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width);
				} else if (allTexturesAreNullAndSameColor[i]){
					atlasMessage.AppendLine("Did not create atlas for " + texPropertyNames[i].name + " because all source textures were null.");
				}	
			}
			report.Append(atlasMessage.ToString());
			
			
			Dictionary<Material,Rect> mat2rect_map = new Dictionary<Material, Rect>();
			for (int i = 0; i < distinctMaterialTextures.Count; i++){
				List<Material> mats = distinctMaterialTextures[i].mats;
				for (int j = 0; j < mats.Count; j++){
					if (!mat2rect_map.ContainsKey(mats[j])){
						mat2rect_map.Add(mats[j],uvRects[i]);
					}
				}
			}
			
			resultAtlasesAndRects.atlases = atlases;                             // one per texture on source shader
			resultAtlasesAndRects.texPropertyNames = ShaderTextureProperty.GetNames(texPropertyNames); // one per texture on source shader
			resultAtlasesAndRects.mat2rect_map = mat2rect_map;
			
			if (progressInfo != null) progressInfo("Restoring Texture Formats & Read Flags",.8f);
			_destroyTemporaryTextures();
			if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			if (report != null && LOG_LEVEL >= MB2_LogLevel.info) Debug.Log(report.ToString());	
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Time Step 3 Create And Save Atlases part 3 " + (sw.ElapsedMilliseconds - t3).ToString("f5"));
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Total time Step 3 Create And Save Atlases " + sw.ElapsedMilliseconds.ToString("f5"));
		}