Improve nine-slice atlas sampling

This commit is contained in:
gem
2026-06-09 14:49:17 +08:00
parent 4ce5fe1ae7
commit 220bb0aba1
3 changed files with 65 additions and 6 deletions

View File

@@ -44,6 +44,7 @@ List<({Rect source, Rect destination})> runtimeNineSliceRects({
double sliceRight = 0,
double sliceBottom = 0,
double destinationOverlap = 0,
double sourceInset = 0,
}) {
if (source.width <= 0 ||
source.height <= 0 ||
@@ -88,7 +89,7 @@ List<({Rect source, Rect destination})> runtimeNineSliceRects({
final parts = <({Rect source, Rect destination})>[];
for (var y = 0; y < 3; y++) {
for (var x = 0; x < 3; x++) {
final sourcePart = Rect.fromLTRB(
final rawSourcePart = Rect.fromLTRB(
sourceXs[x],
sourceYs[y],
sourceXs[x + 1],
@@ -100,12 +101,17 @@ List<({Rect source, Rect destination})> runtimeNineSliceRects({
destXs[x + 1],
destYs[y + 1],
);
if (sourcePart.width <= 0 ||
sourcePart.height <= 0 ||
if (rawSourcePart.width <= 0 ||
rawSourcePart.height <= 0 ||
rawDestPart.width <= 0 ||
rawDestPart.height <= 0) {
continue;
}
final sourcePart = _insetNineSliceSourceRect(
rawSourcePart,
bounds: source,
inset: sourceInset,
);
final destPart = _overlapNineSliceDestinationRect(
rawDestPart,
x: x,
@@ -119,6 +125,22 @@ List<({Rect source, Rect destination})> runtimeNineSliceRects({
return parts;
}
Rect _insetNineSliceSourceRect(
Rect rect, {
required Rect bounds,
required double inset,
}) {
if (inset <= 0 || rect.width <= inset * 2 || rect.height <= inset * 2) {
return rect;
}
return Rect.fromLTRB(
math.min(rect.right, math.max(bounds.left, rect.left + inset)),
math.min(rect.bottom, math.max(bounds.top, rect.top + inset)),
math.max(rect.left, math.min(bounds.right, rect.right - inset)),
math.max(rect.top, math.min(bounds.bottom, rect.bottom - inset)),
);
}
Rect _overlapNineSliceDestinationRect(
Rect rect, {
required int x,
@@ -575,7 +597,13 @@ class RuntimeComponent extends PositionComponent
..color = composeRuntimeColorAlpha(Colors.white, renderAlpha);
final source = _imageSourceRect(image, _currentImageFrame(_node));
if (_usesNineSlice(source, rect)) {
_drawNineSliceImage(canvas, image, source, rect, imagePaint);
_drawNineSliceImage(
canvas,
image,
source,
rect,
imagePaint..filterQuality = FilterQuality.none,
);
} else {
canvas.drawImageRect(image, source, rect, imagePaint);
}
@@ -630,7 +658,8 @@ class RuntimeComponent extends PositionComponent
final parts = runtimeNineSliceRects(
source: source,
destination: destination,
destinationOverlap: 0.5,
destinationOverlap: 1,
sourceInset: 0.5,
sliceLeft: _node.sliceLeft ?? 0,
sliceTop: _node.sliceTop ?? 0,
sliceRight: _node.sliceRight ?? 0,