/// <summary>Adds the given texture to the atlas if it's not already on it,
		/// taking up a set amount of space on the atlas.</summary>
		/// <param name="texture">The texture to add.</param>
		/// <param name="width">The x amount of space to take up on the atlas.</param>
		/// <param name="height">The y amount of space to take up on the atlas.</param>
		/// <returns>The location of the texture on the atlas.</returns>
		internal AtlasLocation Add(AtlasEntity texture,int entityID,int width,int height){
			
			// Pad width/height:
			int spacedWidth=width+RawSpacing;
			int spacedHeight=height+RawSpacing;
			
			// Look for a spot to park this texture in the set of empty blocks.
			
			// The aim is to make it fit in the smallest empty block possible to save space.
			// This is done with a 'fitFactor' - this is simply the difference between the blocks area and the textures area.
			// We want this value to be as small as possible.
			int fitFactor=0;
			AtlasLocation currentAccepted=null;
			
			int area=spacedWidth*spacedHeight;
			
			AtlasLocation currentEmpty=FirstEmpty;
			
			while(currentEmpty!=null){
				int factor=currentEmpty.FitFactor(spacedWidth,spacedHeight,area);
				
				if(factor==0){
					// Perfect fit - break right now; can't beat that!
					currentAccepted=currentEmpty;
					break;
					
				}else if(factor!=-1){
					// We can possibly fit here - is it the current smallest?
					if(currentAccepted==null||factor<fitFactor){
						// Yep! select it.
						fitFactor=factor;
						currentAccepted=currentEmpty;
					}
				}
				
				currentEmpty=currentEmpty.EmptyAfter;
			}
			
			if(Mode==AtlasingMode.Columns && currentAccepted==null){
				
				// Is there any more column space?
				int max=ColumnProgress + spacedWidth;
				
				if(max<=Dimension){
					
					// Yep! Create a location using the remaining space:
					currentAccepted=new AtlasLocation(this,ColumnProgress,0,Dimension-ColumnProgress,Dimension);
					
					// As it's a new location, it's empty by default:
					// (Note that it must be in the empty set, otherwise Select will throw the empty set entirely)
					currentAccepted.AddToEmptySet();
					
				}
				
			}
			
			if(currentAccepted==null){
				// No space in this atlas to fit it in. Stop there.
				
				if(CanOptimize){
					// Request an optimise:
					OptimizeRequested=true;
					Stack.OptimizeRequested=true;
				}
				
				return null;
			}
			
			Stack.ActiveImages[entityID]=currentAccepted;
			
			// And burn in the texture to the location (nb: it internally also writes the pixels to the atlas).
			currentAccepted.Select(texture,width,height,RawSpacing);
			
			return currentAccepted;
		}
		/// <summary>This texture has selected this location to fit into. This adds it to the atlas.</summary>
		/// <param name="texture">The texture that wants to go here.</param>
		/// <param name="width">The width of the texture in pixels.</param>
		/// <param name="height">The height of the texture in pixels.</param>
		public void Select(AtlasEntity image,int width,int height,int spacing){
			// The given texture wants to go in this location.
			// Width and height are given for dynamic textures - textures who's pixels are actually written straight to the atlas.
			Empty=false;
			
			int spacedWidth=width+spacing;
			int spacedHeight=height+spacing;
			
			// Remove from empty queue:
			if(EmptyBefore==null){
				Atlas.FirstEmpty=EmptyAfter;
			}else{
				EmptyBefore.EmptyAfter=EmptyAfter;
			}
			
			if(EmptyAfter==null){
				Atlas.LastEmpty=EmptyBefore;
			}else{
				EmptyAfter.EmptyBefore=EmptyBefore;
			}
			
			int entityID=image.GetAtlasID();
			
			if(AtlasID==entityID){
				// This is a restore - we don't need to do anything else.
				return;
			}
			
			Image=image;
			AtlasID=entityID;
			// If it's not a perfect fit, generate new atlas locations to the right and above of this one.
			
			if(Atlas.Mode==AtlasingMode.SmallestSpace){
			
				if(Width>spacedWidth){
					// The textures a little thin.
					
					// Generate a new area to the right of this one (NB: 0,0 is bottom left)
					AtlasLocation newRight=new AtlasLocation(Atlas,X+spacedWidth,Y,Width-spacedWidth,height);
					// Immediately mark this as empty:
					newRight.AddToEmptySet();
				}
				
				if(Height>spacedHeight){
					// The textures a little short.
					
					// Generate a new area above this one (NB: 0,0 is bottom left)
					AtlasLocation newTop=new AtlasLocation(Atlas,X,Y+spacedHeight,Width,Height-spacedHeight);
					// Immediately mark this as empty:
					newTop.AddToEmptySet();
				}
				
			}else{
				
				int maxX=X+spacedWidth;
				
				if(Atlas.ColumnProgress < maxX){
					
					Atlas.ColumnProgress=maxX;
					
				}
				
				if(Height>spacedHeight){
					// The textures a little short.
					
					// Generate a new area above this one (NB: 0,0 is bottom left)
					AtlasLocation newTop=new AtlasLocation(Atlas,X,Y+spacedHeight,Width,Height-spacedHeight);
					// Immediately mark this as empty:
					newTop.AddToEmptySet();
				}
				
			}
			
			// Set the new size of this location for UV baking:
			Width=width;
			Height=height;
			Spacing=spacing;
			
			// Update the UV's:
			BakeUV();
			
			// Make sure the area is up to date:
			Area=spacedWidth*spacedHeight;
			
			// Write it in:
			Flush();
		}
		/// <summary>Require the given image on any atlas. Note that this may reject the requirement if the image is too big and isn't worthwhile on an atlas.</summary>
		public AtlasLocation RequireImage(AtlasEntity image){
			
			int entityID=image.GetAtlasID();
			
			AtlasLocation result;
			if(ActiveImages.TryGetValue(entityID,out result)){
				// Most calls fall through here.
				return result;
			}
			
			int width;
			int height;
			
			image.GetDimensionsOnAtlas(out width,out height);
			
			if(width>InitialSize || height>InitialSize){
				// Won't fit or is unsuitable for atlasing anyway.
				return null;
			}
			
			if(Last==null){
				Create();
			}else{
				
				// Fast check - was this texture recently removed from any atlas?
				// We might have the chance of restoring it.
				// Their added at the back of the empty queue, so naturally, start at the end of the empty set
				// and go back until we hit one with a null texture.
				
				TextureAtlas currentAtlas=Last;
				
				while(currentAtlas!=null){
					
					AtlasLocation currentE=currentAtlas.LastEmpty;
					
					while(currentE!=null){
						
						if(currentE.Image==null){
							// Nope! Shame.
							break;
						}else if(currentE.AtlasID==entityID){
							// Ace! Time to bring it back from the dead.
							currentE.Select(image,width,height,Spacing);
							ActiveImages[entityID]=currentE;
							
							return currentE;
						}
						
						currentE=currentE.EmptyBefore;
					}
					
					currentAtlas=currentAtlas.Previous;
				}
				
			}
			
			// Push to top of stack:
			result=Last.Add(image,entityID,width,height);
			
			if(result!=null){
				return result;
			}
			
			// Non-fitter - try fitting in lower stack frames:
			
			TextureAtlas current=Last.Previous;
			
			while(current!=null){
				
				result=current.Add(image,entityID,width,height);
				
				if(result!=null){
					return result;
				}
				
				current=current.Previous;
			}
			
			// Still not fitting! Create a new stack frame:
			Create();
			
			return Last.Add(image,entityID,width,height);
			
		}
//--------------------------------------
		/// <summary>Removes a texture from the atlas.</summary>
		/// <param name="texture">The texture to remove.</param>
		public void Remove(AtlasEntity texture){
			if(texture==null){
				return;
			}
			
			AtlasLocation location=Get(texture.GetAtlasID());
			
			if(location==null){
				return;
			}
			
			// Make the location available:
			location.Deselect();
		}