Skip to content

Commit

Permalink
✨ Improve nitro segmentation, layer reduction and fix copying OAM met…
Browse files Browse the repository at this point in the history
…adata
  • Loading branch information
pleonex committed Sep 19, 2023
1 parent 182c767 commit c2c5329
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 34 deletions.
11 changes: 7 additions & 4 deletions src/Texim.Games/Nitro/FullImage2NitroCell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public class FullImage2NitroCell :
{
private FullImage2NitroCellParams parameters;

private int rotationScalingGroup;
private bool hasRotationScaling;
private byte rotationScalingGroup;
private bool hasDoubleSize;
private bool isDisabled;
private bool isMosaic;
Expand All @@ -48,8 +49,10 @@ public void Initialize(FullImage2NitroCellParams parameters)
// We can only guess the original metadata if every original OAMs have it
// otherwise, as original and new OAMs may differ, it's hard to know.
var originalOams = parameters.ReferenceCell.Segments.Cast<ObjectAttributeMemory>().ToArray();
hasRotationScaling = originalOams.DistinctBy(o => o.HasRotationOrScaling).Count() == 1
&& originalOams[0].HasRotationOrScaling;
rotationScalingGroup = originalOams.DistinctBy(o => o.RotationOrScalingGroup).Count() == 1
? originalOams[0].RotationOrScalingGroup : -1;
? originalOams[0].RotationOrScalingGroup : (byte)0;
hasDoubleSize = originalOams.DistinctBy(obj => obj.HasDoubleSize).Count() == 1
&& originalOams[0].HasDoubleSize;
isDisabled = originalOams.DistinctBy(obj => obj.IsDisabled).Count() == 1
Expand Down Expand Up @@ -86,8 +89,8 @@ protected override IImageSegment AssignImageToSegment(IImageSegment segmentStruc
? NitroPaletteMode.Palette256x1
: NitroPaletteMode.Palette16x16;

nitroCell.RotationOrScalingGroup = (rotationScalingGroup != -1) ? (byte)rotationScalingGroup : (byte)0;
nitroCell.HasRotationOrScaling = rotationScalingGroup != -1;
nitroCell.HasRotationOrScaling = hasRotationScaling;
nitroCell.RotationOrScalingGroup = rotationScalingGroup;
nitroCell.HasDoubleSize = hasDoubleSize;
nitroCell.IsMosaic = isMosaic;
nitroCell.IsDisabled = isDisabled;
Expand Down
51 changes: 33 additions & 18 deletions src/Texim.Games/Nitro/NitroImageSegmentation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ namespace Texim.Games.Nitro;
/// </summary>
public class NitroImageSegmentation : IImageSegmentation
{
// We define two modes but only use the second one so far (75% non-transparent)
// For each mode there is a list of tries for width and height.
// First value is the limit and the second is the side.
// From limit to side there must be non-transparent pixels to set it.
// So that it's worthier a bigger cell than two small ones.
private static readonly int[][,] Modes = {
new int[,] { { 32, 64 }, { 16, 32 }, { 8, 16 }, { 0, 8 } }, // 50%
new int[,] { { 48, 64 }, { 24, 32 }, { 8, 16 }, { 0, 8 } }, // 75%
Expand Down Expand Up @@ -108,7 +111,15 @@ private List<IImageSegment> CreateObjects(FullImage frame, int startX, int start
return segments;
}

(int width, int height) = GetObjectSize(frame, x, y, frame.Width, maxHeight - diffY);
int width, height;

// If our cell is already valid, do not split further.
if (IsValidSize(frame.Width, maxHeight - diffY)) {
width = frame.Width;
height = maxHeight - diffY;
} else {
(width, height) = GetObjectSize(frame, x, y, frame.Width, maxHeight - diffY);
}

if (width != 0 && height != 0) {
var segment = new ImageSegment {
Expand Down Expand Up @@ -205,23 +216,27 @@ private List<IImageSegment> CreateObjects(FullImage frame, int startX, int start
Justification = "Readability of the algorithm")]
private static bool IsValidSize(int width, int height)
{
if (width < 0 || width > 64 || width % 8 != 0) {
return false;
}

if (height < 0 || height > 64 || height % 8 != 0) {
return false;
}

if (width == 64 && (height == 8 || height == 16)) {
return false;
}

if ((width == 8 || width == 16) && height == 64) {
return false;
}

return true;
return (width, height) switch {
// Square mode
(8, 8) => true,
(16, 16) => true,
(32, 32) => true,
(64, 64) => true,

// Rectangle horizontal
(16, 8) => true,
(32, 8) => true,
(32, 16) => true,
(64, 32) => true,

// Rectangle vertical
(8, 16) => true,
(8, 32) => true,
(16, 32) => true,
(32, 64) => true,

_ => false,
};
}

private static (int X, int Y, FullImage Trimmed) TrimImage(FullImage image)
Expand Down
31 changes: 19 additions & 12 deletions src/Texim/Formats/Sprite2Tiff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,12 @@ private bool AddSegmentIfSameLayer(IImageSegment segment)
return false;
}

var segmentBounds = new Rectangle(segment.CoordinateX, segment.CoordinateY, segment.Width, segment.Height);
if (IntersectsWithLayer(segment)) {
var segmentBounds = CreateRectangle(segment);
if (IntersectsWithLayer(segmentBounds)) {
return false;
}

if (!IsAdjacentWithLayer(segment)) {
if (!IsAdjacentWithLayer(segmentBounds)) {
return false;
}

Expand All @@ -156,21 +156,28 @@ private bool AddSegmentIfSameLayer(IImageSegment segment)
return true;
}

private bool IntersectsWithLayer(IImageSegment segment)
private bool IntersectsWithLayer(Rectangle segmentBounds)
{
var segmentBounds = CreateRectangle(segment);
return layerSegments.Exists(s => CreateRectangle(s).IntersectsWith(segmentBounds));
}

private bool IsAdjacentWithLayer(IImageSegment segment)
private bool IsAdjacentWithLayer(Rectangle segmentBounds)
{
static bool IsAdjacent(Rectangle rect1, Rectangle rect2) =>
(rect1.Left == rect2.Right)
|| (rect1.Top == rect2.Bottom)
|| (rect1.Right == rect2.Left)
|| (rect1.Bottom == rect2.Top);
static bool IsAdjacent(Rectangle rect1, Rectangle rect2)
{
if ((rect1.Left == rect2.Right) || (rect1.Right == rect2.Left)) {
return ((rect1.Top <= rect2.Top) && (rect1.Bottom >= rect2.Bottom)) ||
((rect2.Top <= rect1.Top) && (rect2.Bottom >= rect1.Bottom));
}

if ((rect1.Top == rect2.Bottom) || (rect1.Bottom == rect2.Top)) {
return ((rect1.Left <= rect2.Left) && (rect1.Right >= rect2.Right)) ||
((rect2.Left <= rect1.Left) && (rect2.Right >= rect1.Right));
}

return false;
}

var segmentBounds = CreateRectangle(segment);
return layerSegments.Exists(s => IsAdjacent(CreateRectangle(s), segmentBounds));
}
}

0 comments on commit c2c5329

Please sign in to comment.