diff --git a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs index 91502a8a..01ee988f 100644 --- a/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs +++ b/PCK-Studio/Forms/Editor/TextureAtlasEditor.cs @@ -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) diff --git a/PCK-Studio/Internal/AppResourceManager.cs b/PCK-Studio/Internal/AppResourceManager.cs new file mode 100644 index 00000000..2f1d2fe9 --- /dev/null +++ b/PCK-Studio/Internal/AppResourceManager.cs @@ -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(byte[] rawData, IDataFormatReader 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(string name, IDataFormatReader dataFormatReader) where T : class + { + return GetData((byte[])_resourceManager.GetObject(name, _culture), dataFormatReader); + } + } +} diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index f55e3c13..a19172de 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -171,6 +171,7 @@ ModelEditor.cs + diff --git a/PckStudio.Core/Atlas.cs b/PckStudio.Core/Atlas.cs index 9c8916f4..d30f19b0 100644 --- a/PckStudio.Core/Atlas.cs +++ b/PckStudio.Core/Atlas.cs @@ -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 _groups; @@ -122,22 +120,19 @@ namespace PckStudio.Core yield break; } - private void SetRange(int row, int col, int count, IEnumerable tiles) + private void SetRange(int row, int col, int count, ImageLayoutDirection direction, IEnumerable 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 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 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 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); + } } } \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroup.cs b/PckStudio.Core/AtlasGroup.cs index f571014f..3b2a53f0 100644 --- a/PckStudio.Core/AtlasGroup.cs +++ b/PckStudio.Core/AtlasGroup.cs @@ -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); } } \ No newline at end of file diff --git a/PckStudio.Core/AtlasGroupAnimation.cs b/PckStudio.Core/AtlasGroupAnimation.cs index 233a715a..aa3e6883 100644 --- a/PckStudio.Core/AtlasGroupAnimation.cs +++ b/PckStudio.Core/AtlasGroupAnimation.cs @@ -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) diff --git a/PckStudio.Core/AtlasGroupLargeTile.cs b/PckStudio.Core/AtlasGroupLargeTile.cs index d81bed39..7475cf4f 100644 --- a/PckStudio.Core/AtlasGroupLargeTile.cs +++ b/PckStudio.Core/AtlasGroupLargeTile.cs @@ -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) diff --git a/PckStudio.Core/AtlasGroupLargeTileAnimation.cs b/PckStudio.Core/AtlasGroupLargeTileAnimation.cs index 1e4937d3..4efdb43e 100644 --- a/PckStudio.Core/AtlasGroupLargeTileAnimation.cs +++ b/PckStudio.Core/AtlasGroupLargeTileAnimation.cs @@ -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) diff --git a/PckStudio.Core/AtlasTile.cs b/PckStudio.Core/AtlasTile.cs index 0da75b12..093978c8 100644 --- a/PckStudio.Core/AtlasTile.cs +++ b/PckStudio.Core/AtlasTile.cs @@ -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;