/// <summary>Attempts to add the "remote" atlas location to this atlas. /// The original location object is retained.</summary> /// <returns>True if this atlas accepted the location.</summary> internal bool OptimiseAdd(AtlasLocation location) { int fitFactor = 0; int area = location.Area; AtlasLocation currentAccepted = null; AtlasLocation currentEmpty = FirstEmpty; while (currentEmpty != null) { int factor = currentEmpty.FitFactor(location.Width, location.Height, 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 (currentAccepted == null) { return(false); } // We've got a block of space that we'll be "adding" to. // Note that we're going to *keep* the original location. currentAccepted.OptimiseSelect(location); return(true); }
/// <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. AtlasLocation currentAccepted = null; int area = spacedWidth * spacedHeight; if (Mode == AtlasingMode.Columns) { // Space in this column? int max = ColumnProgressY + spacedHeight; if (max <= Dimension) { // Yep! Create a location here: currentAccepted = new AtlasLocation(this, ColumnProgressX, ColumnProgressY, spacedWidth, spacedHeight); // Move it: ColumnProgressY += spacedHeight; if (spacedWidth > ColumnWidth) { // Update width: ColumnWidth = spacedWidth; } // 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(); } else { // Space to generate a new column? max = ColumnProgressX + ColumnWidth + spacedWidth; if (max <= Dimension) { // Set Y: ColumnProgressY = spacedHeight; // Move X: ColumnProgressX += ColumnWidth; // Yep! Create a location here: currentAccepted = new AtlasLocation(this, ColumnProgressX, 0, spacedWidth, spacedHeight); // Reset width: ColumnWidth = spacedWidth; // 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(); } // Otherwise, the atlas is practically full. // We're gonna just reject the add (by falling below), and state that it can be optimised. // This triggers another atlas to get created and this one will // be optimised at some point in the near future. } } else { int fitFactor = 0; 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 (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>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); }