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 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
|
- 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
|
## 6.1.0
|
||||||
|
|
||||||
### MLEM
|
### MLEM
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace MLEM.Data {
|
||||||
|
|
||||||
private readonly List<Request> texturesToPack = new List<Request>();
|
private readonly List<Request> texturesToPack = new List<Request>();
|
||||||
private readonly List<Request> packedTextures = 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 Dictionary<Texture2D, TextureData> dataCache = new Dictionary<Texture2D, TextureData>();
|
||||||
private readonly bool autoIncreaseMaxWidth;
|
private readonly bool autoIncreaseMaxWidth;
|
||||||
private readonly bool forcePowerOfTwo;
|
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
|
// we pack larger textures first, so that smaller textures can fit in the gaps that larger ones leave
|
||||||
var stopwatch = Stopwatch.StartNew();
|
var stopwatch = Stopwatch.StartNew();
|
||||||
foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
|
foreach (var request in this.texturesToPack.OrderByDescending(t => t.Texture.Width * t.Texture.Height)) {
|
||||||
request.PackedArea = this.FindFreeArea(request);
|
request.PackedArea = this.OccupyFreeArea(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;
|
|
||||||
this.packedTextures.Add(request);
|
this.packedTextures.Add(request);
|
||||||
}
|
}
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
|
@ -224,7 +222,7 @@ namespace MLEM.Data {
|
||||||
this.LastPackTime = TimeSpan.Zero;
|
this.LastPackTime = TimeSpan.Zero;
|
||||||
this.texturesToPack.Clear();
|
this.texturesToPack.Clear();
|
||||||
this.packedTextures.Clear();
|
this.packedTextures.Clear();
|
||||||
this.firstPossiblePosForSize.Clear();
|
this.occupiedPositions.Clear();
|
||||||
this.dataCache.Clear();
|
this.dataCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,31 +231,42 @@ namespace MLEM.Data {
|
||||||
this.Reset();
|
this.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rectangle FindFreeArea(Request request) {
|
private Rectangle OccupyFreeArea(Request request) {
|
||||||
var size = new Point(request.Texture.Width, request.Texture.Height);
|
var size = new Point(request.Texture.Width, request.Texture.Height);
|
||||||
size.X += request.Padding * 2;
|
size.X += request.Padding * 2;
|
||||||
size.Y += 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;
|
var lowestY = int.MaxValue;
|
||||||
while (true) {
|
while (true) {
|
||||||
var intersected = false;
|
// check if the current area is already occupied
|
||||||
var area = new Rectangle(pos.X, pos.Y, size.X, size.Y);
|
if (!this.occupiedPositions.TryGetValue(area.Location, out var existing)) {
|
||||||
foreach (var tex in this.packedTextures) {
|
existing = this.packedTextures.FirstOrDefault(t => t.PackedArea.Intersects(area));
|
||||||
if (tex.PackedArea.Intersects(area)) {
|
if (existing == null) {
|
||||||
pos.X = tex.PackedArea.Right;
|
// if no texture is occupying this space, we have found a free area
|
||||||
// when we move down, we want to move down by the smallest intersecting texture's height
|
this.occupiedPositions.Add(area.Location, request);
|
||||||
if (lowestY > tex.PackedArea.Bottom)
|
return area;
|
||||||
lowestY = tex.PackedArea.Bottom;
|
|
||||||
intersected = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// also cache the existing texture for this position, in case we check it again in the future
|
||||||
|
this.occupiedPositions.Add(area.Location, existing);
|
||||||
}
|
}
|
||||||
if (!intersected)
|
|
||||||
return area;
|
// move to the right by the existing texture's width
|
||||||
if (pos.X + size.X > this.maxWidth) {
|
area.X = existing.PackedArea.Right;
|
||||||
pos.X = 0;
|
|
||||||
pos.Y = lowestY;
|
// 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;
|
lowestY = int.MaxValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue