/// <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>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>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(); }