mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-22 04:53:29 +01:00
Improved RuntimeTexturePacker performance for differently sized textures
This commit is contained in:
parent
e623eff02d
commit
99b45b09d9
2 changed files with 35 additions and 22 deletions
|
@ -47,6 +47,10 @@ Fixes
|
|||
- Fixed Paragraph and Checkbox not reacting to SquishingGroup sizing properly
|
||||
- Fixed TextInput and Slider still reacting to input when they are selected, but not part of the active root
|
||||
|
||||
### MLEM.Data
|
||||
Improvements
|
||||
- Improved RuntimeTexturePacker performance for differently sized textures
|
||||
|
||||
## 6.1.0
|
||||
|
||||
### MLEM
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace MLEM.Data {
|
|||
|
||||
private readonly List<Request> texturesToPack = new List<Request>();
|
||||
private readonly List<Request> packedTextures = new List<Request>();
|
||||
private readonly Dictionary<Point, Point> firstPossiblePosForSize = new Dictionary<Point, Point>();
|
||||
private readonly Dictionary<Point, Request> occupiedPositions = new Dictionary<Point, Request>();
|
||||
private readonly Dictionary<Texture2D, TextureData> dataCache = new Dictionary<Texture2D, TextureData>();
|
||||
private readonly bool autoIncreaseMaxWidth;
|
||||
private readonly bool forcePowerOfTwo;
|
||||
|
@ -162,9 +162,7 @@ namespace MLEM.Data {
|
|||
// we pack larger textures first, so that smaller textures can fit in the gaps that larger ones leave
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
|
||||
request.PackedArea = this.FindFreeArea(request);
|
||||
// if this is the first position that this request fit in, no other requests of the same size will find a position before it
|
||||
this.firstPossiblePosForSize[new Point(request.PackedArea.Width, request.PackedArea.Height)] = request.PackedArea.Location;
|
||||
request.PackedArea = this.OccupyFreeArea(request);
|
||||
this.packedTextures.Add(request);
|
||||
}
|
||||
stopwatch.Stop();
|
||||
|
@ -224,7 +222,7 @@ namespace MLEM.Data {
|
|||
this.LastPackTime = TimeSpan.Zero;
|
||||
this.texturesToPack.Clear();
|
||||
this.packedTextures.Clear();
|
||||
this.firstPossiblePosForSize.Clear();
|
||||
this.occupiedPositions.Clear();
|
||||
this.dataCache.Clear();
|
||||
}
|
||||
|
||||
|
@ -233,31 +231,42 @@ namespace MLEM.Data {
|
|||
this.Reset();
|
||||
}
|
||||
|
||||
private Rectangle FindFreeArea(Request request) {
|
||||
private Rectangle OccupyFreeArea(Request request) {
|
||||
var size = new Point(request.Texture.Width, request.Texture.Height);
|
||||
size.X += request.Padding * 2;
|
||||
size.Y += request.Padding * 2;
|
||||
|
||||
var pos = this.firstPossiblePosForSize.TryGetValue(size, out var first) ? first : Point.Zero;
|
||||
// exit early if the texture doesn't need to find a free location
|
||||
if (size.X <= 0 || size.Y <= 0)
|
||||
return Rectangle.Empty;
|
||||
|
||||
var area = new Rectangle(Point.Zero, size);
|
||||
var lowestY = int.MaxValue;
|
||||
while (true) {
|
||||
var intersected = false;
|
||||
var area = new Rectangle(pos.X, pos.Y, size.X, size.Y);
|
||||
foreach (var tex in this.packedTextures) {
|
||||
if (tex.PackedArea.Intersects(area)) {
|
||||
pos.X = tex.PackedArea.Right;
|
||||
// when we move down, we want to move down by the smallest intersecting texture's height
|
||||
if (lowestY > tex.PackedArea.Bottom)
|
||||
lowestY = tex.PackedArea.Bottom;
|
||||
intersected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!intersected)
|
||||
// check if the current area is already occupied
|
||||
if (!this.occupiedPositions.TryGetValue(area.Location, out var existing)) {
|
||||
existing = this.packedTextures.FirstOrDefault(t => t.PackedArea.Intersects(area));
|
||||
if (existing == null) {
|
||||
// if no texture is occupying this space, we have found a free area
|
||||
this.occupiedPositions.Add(area.Location, request);
|
||||
return area;
|
||||
if (pos.X + size.X > this.maxWidth) {
|
||||
pos.X = 0;
|
||||
pos.Y = lowestY;
|
||||
}
|
||||
|
||||
// also cache the existing texture for this position, in case we check it again in the future
|
||||
this.occupiedPositions.Add(area.Location, existing);
|
||||
}
|
||||
|
||||
// move to the right by the existing texture's width
|
||||
area.X = existing.PackedArea.Right;
|
||||
|
||||
// remember the smallest intersecting texture's height for when we move down
|
||||
if (lowestY > existing.PackedArea.Bottom)
|
||||
lowestY = existing.PackedArea.Bottom;
|
||||
|
||||
// move down a row if we exceed our maximum width
|
||||
if (area.Right > this.maxWidth) {
|
||||
area.X = 0;
|
||||
area.Y = lowestY;
|
||||
lowestY = int.MaxValue;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue