TextureAtlas - Impl extraction&import of large tiles

This commit is contained in:
miku-666
2025-11-09 08:25:11 +01:00
parent 38a3294d4b
commit 94f264c609
9 changed files with 113 additions and 38 deletions

View File

@@ -16,19 +16,22 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Linq;
using System.Drawing;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Windows.Forms;
using OMI.Formats.Color;
using OMI.Workers.Color;
using PckStudio.Controls;
using PckStudio.Core;
using PckStudio.Core.Extensions;
using PckStudio.Interfaces;
using PckStudio.Controls;
using OMI.Formats.Color;
using PckStudio.Core.Json;
using PckStudio.Interfaces;
using PckStudio.Internal;
using PckStudio.Properties;
namespace PckStudio.Forms.Editor
{
@@ -50,16 +53,15 @@ namespace PckStudio.Forms.Editor
_ = atlas ?? throw new ArgumentNullException(nameof(atlas));
_ = resourceLocation ?? throw new ArgumentNullException(nameof(resourceLocation));
_atlas = atlas;
Text = _atlas.Name;
originalPictureBox.Image = atlas;
_colourTable = colorContainer ?? new ColorContainer();
_colourTable = colorContainer ?? AppResourceManager.Default.GetData(Resources.tu69colours, new COLFileReader());
_tryGetAnimation = tryGetAnimation;
_tryGetAnimationSaveContext = tryGetAnimationSaveContext;
_atlas = atlas;
_resourceLocationCategory = resourceLocation.Category;
_atlas.AllowGroups = allowGroupsToolStripMenuItem.Checked;
SelectedIndex = 0;
animationButton.Enabled =
@@ -110,7 +112,7 @@ namespace PckStudio.Forms.Editor
g.DrawImage(image, 0, 0, image.Width, image.Height);
SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.White));
g.FillRectangle(brush, _atlas.GetTileArea(_selectedTile));
g.FillRectangle(brush, allowGroupsToolStripMenuItem.Checked ? _atlas.GetTileArea(_selectedTile) : _selectedTile.GetArea(_atlas.TileSize));
}
originalPictureBox.Invalidate();
}
@@ -294,6 +296,15 @@ namespace PckStudio.Forms.Editor
private void SetTile(Image texture)
{
if (_selectedTile.IsPartOfGroup)
{
AtlasGroup group = _selectedTile.GetGroup();
_atlas.SetGroup(group, texture);
selectTilePictureBox.Image = _atlas.GetTileTexture(_selectedTile);
UpdateAtlasDisplay();
return;
}
if (texture.Size != _atlas.TileSize)
texture = texture.Resize(_atlas.TileSize, _graphicsConfig);
@@ -415,7 +426,7 @@ namespace PckStudio.Forms.Editor
if (fileDialog.ShowDialog(this) == DialogResult.OK)
{
var img = Image.FromFile(fileDialog.FileName);
Image img = Image.FromFile(fileDialog.FileName).ReleaseFromFile();
SetTile(img);
}
}
@@ -457,10 +468,9 @@ namespace PckStudio.Forms.Editor
}
}
// TODO
private void extractTileToolStripMenuItem_Click(object sender, EventArgs e)
{
string filename = _selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) ? tileInfo.InternalName : "tile";
string filename = GetSanitizedFilename();
SaveFileDialog saveFileDialog = new SaveFileDialog()
{
Filter = "Tile Texture|*.png",
@@ -468,10 +478,22 @@ namespace PckStudio.Forms.Editor
};
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
{
_selectedTile.Texture.Save(saveFileDialog.FileName, ImageFormat.Png);
_atlas.GetTileTexture(_selectedTile).Save(saveFileDialog.FileName, ImageFormat.Png);
}
}
private string GetSanitizedFilename()
{
if (_selectedTile.IsPartOfGroup)
{
AtlasGroup group = _selectedTile.GetGroup();
return group.Name.Replace(' ', '_').Trim().ToLower();
}
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && !string.IsNullOrWhiteSpace(tileInfo.InternalName))
return tileInfo.InternalName;
return "tile";
}
private void variantComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && variantComboBox.SelectedItem is not null)

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using OMI.Workers;
using PckStudio.Properties;
namespace PckStudio.Internal
{
internal sealed class AppResourceManager
{
public static readonly AppResourceManager Default = new AppResourceManager(Resources.ResourceManager, Resources.Culture);
private ResourceManager _resourceManager;
private readonly CultureInfo _culture;
public AppResourceManager(ResourceManager resourceManager, CultureInfo culture)
{
_resourceManager = resourceManager ?? throw new ArgumentNullException(nameof(resourceManager));
_culture = culture;
}
public T GetData<T>(byte[] rawData, IDataFormatReader<T> dataFormatReader) where T : class
{
_ = rawData ?? throw new ArgumentNullException(nameof(rawData));
_ = dataFormatReader ?? throw new ArgumentNullException(nameof(dataFormatReader));
T result = default;
using (Stream resourceStream = new MemoryStream(rawData))
{
result = dataFormatReader.FromStream(resourceStream);
}
return result;
}
public T GetDataFromResource<T>(string name, IDataFormatReader<T> dataFormatReader) where T : class
{
return GetData((byte[])_resourceManager.GetObject(name, _culture), dataFormatReader);
}
}
}

View File

@@ -171,6 +171,7 @@
<DependentUpon>ModelEditor.cs</DependentUpon>
</Compile>
<Compile Include="Internal\ApplicationScope.cs" />
<Compile Include="Internal\AppResourceManager.cs" />
<Compile Include="Internal\CommitInfo.cs" />
<Compile Include="Internal\Entities.cs" />
<Compile Include="Internal\RichPresenceClient.cs" />

View File

@@ -32,8 +32,6 @@ namespace PckStudio.Core
public Size TileSize { get; }
public int TileCount => _tiles.Length;
public bool AllowGroups { get; set; } = default;
private readonly AtlasTile[] _tiles;
private readonly ImageLayoutDirection _layoutDirection;
private readonly List<AtlasGroup> _groups;
@@ -122,22 +120,19 @@ namespace PckStudio.Core
yield break;
}
private void SetRange(int row, int col, int count, IEnumerable<Image> tiles)
private void SetRange(int row, int col, int count, ImageLayoutDirection direction, IEnumerable<Image> tiles)
=> SetRange(row, col, direction == ImageLayoutDirection.Horizontal ? count : 1, direction == ImageLayoutDirection.Vertical ? count : 1, tiles);
private void SetRange(int row, int col, int rowCount, int columnCount, IEnumerable<Image> tiles)
{
Image[] atlasTiles = tiles.ToArray();
if (atlasTiles.Length < count)
return;
count = count < atlasTiles.Length ? count : atlasTiles.Length;
for (int i = 0; i < count; i++)
for (int j = 0; j < columnCount; j++)
{
if (row < Rows)
for (int i = 0; i < rowCount; i++)
{
this[row++, col].Texture = atlasTiles[i];
}
else
{
row %= Rows;
this[row, col++].Texture = atlasTiles[i];
if ((row + i) < Rows && (col + j) < Columns)
{
this[row + i, col + j].Texture = atlasTiles[(j * rowCount) + i];
}
}
}
}
@@ -179,7 +174,7 @@ namespace PckStudio.Core
public void SetGroupTilesFromAnimation(AtlasGroup group, Animation animation)
{
SetRange(group.Row, group.Column, group.Count, animation.GetFrames().Select(f => f.Texture));
SetRange(group.Row, group.Column, group.Count, group.Direction, animation.GetFrames().Select(f => f.Texture));
}
private IEnumerable<AtlasTile> GetLargeTile(AtlasGroupLargeTile group) => GetRange(group.Row, group.Column, group.RowSpan, group.ColumnSpan);
@@ -218,10 +213,19 @@ namespace PckStudio.Core
public Rectangle GetTileArea(AtlasTile tile)
{
if (!tile.IsPartOfGroup || !AllowGroups)
return new Rectangle(new Point(tile.Row * TileSize.Width, tile.Column * TileSize.Height), TileSize);
if (!tile.IsPartOfGroup)
return tile.GetArea(TileSize);
AtlasGroup group = tile.GetGroup();
return new Rectangle(new Point(group.Row * TileSize.Width, group.Column * TileSize.Height), group.GetSize(TileSize));
}
public void SetGroup(AtlasGroup group, Image texture)
{
IEnumerable<Image> images = texture.Split(TileSize, group.Direction);
if (!images.All(img => img.Size == TileSize))
return;
Size s = group.GetSize(new Size(1, 1));
SetRange(group.Row, group.Column, s.Width, s.Height, images);
}
}
}

View File

@@ -42,7 +42,7 @@ namespace PckStudio.Core
public bool IsAnimation() => isAnimation;
public bool IsLargeTile() => isLargeTile;
internal abstract Size GetSize(Size tileSize);
public abstract Size GetSize(Size tileSize);
}
}

View File

@@ -29,7 +29,7 @@ namespace PckStudio.Core
protected override bool isLargeTile => false;
internal override Size GetSize(Size tileSize) => new Size(tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? Count : 1), tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? Count : 1));
public override Size GetSize(Size tileSize) => new Size(tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? Count : 1), tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? Count : 1));
public AtlasGroupAnimation(string name, int row, int column, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime)
: base(name, row, column)

View File

@@ -31,7 +31,7 @@ namespace PckStudio.Core
protected override bool isLargeTile => true;
internal override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width, ColumnSpan * tileSize.Height);
public override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width, ColumnSpan * tileSize.Height);
public AtlasGroupLargeTile(string name, int row, int column, int rowSpan, int columnSpan)
: base(name, row, column)

View File

@@ -39,7 +39,7 @@ namespace PckStudio.Core
protected override bool isLargeTile => true;
internal override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1), ColumnSpan * tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? _frameCount : 1));
public override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1), ColumnSpan * tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? _frameCount : 1));
public AtlasGroupLargeTileAnimation(string name, int row, int column, int rowSpan, int columnSpan, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime)
: base(name, row, column)

View File

@@ -15,6 +15,7 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
using System;
using System.Drawing;
namespace PckStudio.Core
@@ -47,6 +48,8 @@ namespace PckStudio.Core
}
public AtlasGroup GetGroup() => _group;
public Rectangle GetArea(Size tileSize) => new Rectangle(new Point(Row * tileSize.Width, Column * tileSize.Height), tileSize);
public static implicit operator Image(AtlasTile tile) => tile.Texture;