mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-05-24 01:35:41 +00:00
Added TextureAtlasEditor.cs and moved some extension methods
This commit is contained in:
@@ -11,11 +11,11 @@ namespace PckStudio.Extensions
|
||||
{
|
||||
public GraphicsConfig()
|
||||
{
|
||||
CompositingQuality = CompositingQuality.Default;
|
||||
InterpolationMode = InterpolationMode.Default;
|
||||
SmoothingMode = SmoothingMode.Default;
|
||||
PixelOffsetMode = PixelOffsetMode.Default;
|
||||
CompositingMode = CompositingMode.SourceOver;
|
||||
CompositingQuality = default;
|
||||
InterpolationMode = default;
|
||||
SmoothingMode = default;
|
||||
PixelOffsetMode = default;
|
||||
CompositingMode = default;
|
||||
}
|
||||
|
||||
public CompositingMode CompositingMode { get; set; }
|
||||
@@ -35,5 +35,14 @@ namespace PckStudio.Extensions
|
||||
graphics.SmoothingMode = config.SmoothingMode;
|
||||
graphics.PixelOffsetMode = config.PixelOffsetMode;
|
||||
}
|
||||
|
||||
internal static Graphics Fill(this Graphics graphics, Rectangle area, Color color)
|
||||
{
|
||||
var clip = graphics.Clip;
|
||||
graphics.SetClip(area, CombineMode.Replace);
|
||||
graphics.Clear(color);
|
||||
graphics.SetClip(clip, CombineMode.Replace);
|
||||
return graphics;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +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;
|
||||
using System.Drawing;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -125,6 +125,11 @@ namespace PckStudio.Extensions
|
||||
return new Size(width, height);
|
||||
}
|
||||
|
||||
internal static Image ResizeImage(this Image image, Size size, GraphicsConfig graphicsConfig)
|
||||
{
|
||||
return image.ResizeImage(size.Width, size.Height, graphicsConfig);
|
||||
}
|
||||
|
||||
internal static Image ResizeImage(this Image image, int width, int height, GraphicsConfig graphicsConfig)
|
||||
{
|
||||
var destRect = new Rectangle(0, 0, width, height);
|
||||
@@ -144,18 +149,6 @@ namespace PckStudio.Extensions
|
||||
return destImage;
|
||||
}
|
||||
|
||||
internal static Image Fill(this Image image, Color color)
|
||||
{
|
||||
using (var g = Graphics.FromImage(image))
|
||||
{
|
||||
using (SolidBrush brush = new SolidBrush(color))
|
||||
{
|
||||
g.FillRectangle(brush, new Rectangle(Point.Empty, image.Size));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
internal static Image Blend(this Image image, Color overlayColor, BlendMode mode)
|
||||
{
|
||||
if (image is not Bitmap baseImage)
|
||||
|
||||
@@ -11,5 +11,10 @@ namespace PckStudio.Extensions
|
||||
list[index2] = temp;
|
||||
return list;
|
||||
}
|
||||
|
||||
public static bool IndexInRange<T>(this IList<T> list, int index)
|
||||
{
|
||||
return index >= 0 && index < list.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,12 +63,11 @@ namespace PckStudio.Forms.Editor
|
||||
public Animation(IEnumerable<Image> textures)
|
||||
{
|
||||
this.textures = new List<Image>(textures);
|
||||
AddSingleFrames();
|
||||
}
|
||||
|
||||
public Animation(IEnumerable<Image> textures, string ANIM)
|
||||
: this(textures)
|
||||
{
|
||||
this.textures = new List<Image>(textures);
|
||||
ParseAnim(ANIM);
|
||||
}
|
||||
|
||||
@@ -89,7 +88,11 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private void ParseAnim(string anim)
|
||||
{
|
||||
_ = anim ?? throw new ArgumentNullException(nameof(anim));
|
||||
if (string.IsNullOrEmpty(anim))
|
||||
{
|
||||
AddSingleFrames();
|
||||
return;
|
||||
}
|
||||
anim = anim.Trim();
|
||||
anim = (Interpolate = anim.StartsWith("#")) ? anim.Substring(1) : anim;
|
||||
string[] animData = anim.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
@@ -119,7 +122,7 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private void CheckTextureIndex(int index)
|
||||
{
|
||||
if ((index < 0 || index >= textures.Count))
|
||||
if (!textures.IndexInRange(index))
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,8 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
toolStripSeparator1.Visible = saveToolStripMenuItem1.Visible = !Settings.Default.AutoSaveChanges;
|
||||
|
||||
if (animationFile.Size > 0)
|
||||
currentAnimation = new Animation(Array.Empty<Image>());
|
||||
if (animationFile.Size > 0)
|
||||
{
|
||||
using MemoryStream textureMem = new MemoryStream(animationFile.Data);
|
||||
var texture = new Bitmap(textureMem);
|
||||
@@ -53,9 +54,9 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
currentAnimation = animationFile.Properties.HasProperty("ANIM")
|
||||
? new Animation(frameTextures, animationFile.Properties.GetPropertyValue("ANIM"))
|
||||
: new Animation(frameTextures);
|
||||
: new Animation(frameTextures, string.Empty);
|
||||
}
|
||||
currentAnimation.Category = animationFile.Filename.Split('/').Contains("items")
|
||||
currentAnimation.Category = animationFile.Filename.Split('/').Contains("items")
|
||||
? Animation.AnimationCategory.Items
|
||||
: Animation.AnimationCategory.Blocks;
|
||||
SetTileLabel();
|
||||
@@ -83,7 +84,10 @@ namespace PckStudio.Forms.Editor
|
||||
SelectedImageIndex = imageIndex,
|
||||
});
|
||||
}
|
||||
animationPictureBox.SelectFrame(currentAnimation, 0);
|
||||
if (currentAnimation.FrameCount > 0)
|
||||
{
|
||||
animationPictureBox.SelectFrame(currentAnimation, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void frameTreeView_AfterSelect(object sender, TreeViewEventArgs e)
|
||||
@@ -296,9 +300,10 @@ namespace PckStudio.Forms.Editor
|
||||
MessageBox.Show(textureFile + " was not found", "Texture not found");
|
||||
return;
|
||||
}
|
||||
var textures = Image.FromFile(textureFile).CreateImageList(ImageLayoutDirection.Horizontal);
|
||||
var textures = Image.FromFile(textureFile).CreateImageList(ImageLayoutDirection.Vertical);
|
||||
var new_animation = new Animation(textures);
|
||||
try
|
||||
new_animation.Category = currentAnimation.Category;
|
||||
try
|
||||
{
|
||||
JObject mcmeta = JObject.Parse(File.ReadAllText(fileDialog.FileName));
|
||||
if (mcmeta["animation"] is JToken animation)
|
||||
@@ -479,7 +484,7 @@ namespace PckStudio.Forms.Editor
|
||||
gif.SelectActiveFrame(dimension, i);
|
||||
textures.Add(new Bitmap(gif));
|
||||
}
|
||||
currentAnimation = new Animation(textures);
|
||||
currentAnimation = new Animation(textures, string.Empty);
|
||||
LoadAnimationTreeView();
|
||||
}
|
||||
|
||||
@@ -494,7 +499,7 @@ namespace PckStudio.Forms.Editor
|
||||
return;
|
||||
Image img = Image.FromFile(ofd.FileName);
|
||||
var textures = img.CreateImageList(ImageLayoutDirection.Vertical);
|
||||
currentAnimation = new Animation(textures);
|
||||
currentAnimation = new Animation(textures, string.Empty);
|
||||
LoadAnimationTreeView();
|
||||
}
|
||||
|
||||
|
||||
@@ -106,12 +106,11 @@ namespace PckStudio.Forms.Editor
|
||||
for (int tick = 0; tick < currentFrame.Ticks && !cts.IsCancellationRequested; tick++)
|
||||
{
|
||||
double delta = 1.0f - tick / (double)currentFrame.Ticks;
|
||||
if (!IsDisposed)
|
||||
Invoke(() =>
|
||||
{
|
||||
if (!IsDisposed)
|
||||
Image = currentFrame.Texture.Interpolate(nextFrame.Texture, delta);
|
||||
});
|
||||
Invoke(() =>
|
||||
{
|
||||
if (!Disposing)
|
||||
Image = currentFrame.Texture.Interpolate(nextFrame.Texture, delta);
|
||||
});
|
||||
await Task.Delay(TickInMillisecond);
|
||||
}
|
||||
}
|
||||
|
||||
259
PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs
generated
Normal file
259
PCK-Studio/Forms/Editor/TextureAtlasEditor.Designer.cs
generated
Normal file
@@ -0,0 +1,259 @@
|
||||
namespace PckStudio
|
||||
{
|
||||
partial class TextureAtlasEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TextureAtlasEditor));
|
||||
this.prevButton = new MetroFramework.Controls.MetroButton();
|
||||
this.nextButton = new MetroFramework.Controls.MetroButton();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.extractTileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.originalPictureBox = new PckStudio.PictureBoxWithInterpolationMode();
|
||||
this.selectImagePictureBox = new PckStudio.PictureBoxWithInterpolationMode();
|
||||
this.infoTextBox = new System.Windows.Forms.RichTextBox();
|
||||
this.replaceButton = new MetroFramework.Controls.MetroButton();
|
||||
this.animationButton = new MetroFramework.Controls.MetroButton();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.originalPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.selectImagePictureBox)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// prevButton
|
||||
//
|
||||
this.prevButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.prevButton.Enabled = false;
|
||||
this.prevButton.Location = new System.Drawing.Point(3, 210);
|
||||
this.prevButton.Name = "prevButton";
|
||||
this.prevButton.Size = new System.Drawing.Size(145, 19);
|
||||
this.prevButton.TabIndex = 1;
|
||||
this.prevButton.Text = "Prev.";
|
||||
this.prevButton.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.prevButton.UseSelectable = true;
|
||||
this.prevButton.Click += new System.EventHandler(this.prevButton_Click);
|
||||
//
|
||||
// nextButton
|
||||
//
|
||||
this.nextButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.nextButton.Enabled = false;
|
||||
this.nextButton.Location = new System.Drawing.Point(154, 210);
|
||||
this.nextButton.Name = "nextButton";
|
||||
this.nextButton.Size = new System.Drawing.Size(145, 19);
|
||||
this.nextButton.TabIndex = 2;
|
||||
this.nextButton.Text = "Next";
|
||||
this.nextButton.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.nextButton.UseSelectable = true;
|
||||
this.nextButton.Click += new System.EventHandler(this.nextButton_Click);
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
this.menuStrip1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(20, 60);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(759, 24);
|
||||
this.menuStrip1.TabIndex = 16;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// fileToolStripMenuItem
|
||||
//
|
||||
this.fileToolStripMenuItem.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
|
||||
this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.saveToolStripMenuItem,
|
||||
this.extractTileToolStripMenuItem});
|
||||
this.fileToolStripMenuItem.ForeColor = System.Drawing.SystemColors.Menu;
|
||||
this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
|
||||
this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
|
||||
this.fileToolStripMenuItem.Text = "File";
|
||||
//
|
||||
// saveToolStripMenuItem
|
||||
//
|
||||
this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
|
||||
this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.saveToolStripMenuItem.Text = "Save";
|
||||
this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click);
|
||||
//
|
||||
// extractTileToolStripMenuItem
|
||||
//
|
||||
this.extractTileToolStripMenuItem.Name = "extractTileToolStripMenuItem";
|
||||
this.extractTileToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.extractTileToolStripMenuItem.Text = "Extract Tile";
|
||||
this.extractTileToolStripMenuItem.Click += new System.EventHandler(this.extractTileToolStripMenuItem_Click);
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.AutoSize = true;
|
||||
this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||
this.tableLayoutPanel1.ColumnCount = 3;
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 60F));
|
||||
this.tableLayoutPanel1.Controls.Add(this.prevButton, 0, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.nextButton, 1, 1);
|
||||
this.tableLayoutPanel1.Controls.Add(this.originalPictureBox, 2, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.selectImagePictureBox, 0, 0);
|
||||
this.tableLayoutPanel1.Controls.Add(this.infoTextBox, 0, 2);
|
||||
this.tableLayoutPanel1.Controls.Add(this.replaceButton, 0, 4);
|
||||
this.tableLayoutPanel1.Controls.Add(this.animationButton, 0, 3);
|
||||
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel1.Location = new System.Drawing.Point(20, 84);
|
||||
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
|
||||
this.tableLayoutPanel1.RowCount = 5;
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 38.09524F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 4.761905F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 47.61905F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 4.761905F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 4.761905F));
|
||||
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(759, 545);
|
||||
this.tableLayoutPanel1.TabIndex = 17;
|
||||
//
|
||||
// originalPictureBox
|
||||
//
|
||||
this.originalPictureBox.BackColor = System.Drawing.Color.Transparent;
|
||||
this.originalPictureBox.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.originalPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
this.originalPictureBox.Location = new System.Drawing.Point(305, 3);
|
||||
this.originalPictureBox.Name = "originalPictureBox";
|
||||
this.tableLayoutPanel1.SetRowSpan(this.originalPictureBox, 5);
|
||||
this.originalPictureBox.Size = new System.Drawing.Size(451, 539);
|
||||
this.originalPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.originalPictureBox.TabIndex = 4;
|
||||
this.originalPictureBox.TabStop = false;
|
||||
this.originalPictureBox.MouseClick += new System.Windows.Forms.MouseEventHandler(this.originalPictureBox_MouseClick);
|
||||
//
|
||||
// selectImagePictureBox
|
||||
//
|
||||
this.selectImagePictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.selectImagePictureBox.BackColor = System.Drawing.Color.Transparent;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.selectImagePictureBox, 2);
|
||||
this.selectImagePictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
this.selectImagePictureBox.Location = new System.Drawing.Point(3, 3);
|
||||
this.selectImagePictureBox.Name = "selectImagePictureBox";
|
||||
this.selectImagePictureBox.Size = new System.Drawing.Size(296, 201);
|
||||
this.selectImagePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
||||
this.selectImagePictureBox.TabIndex = 0;
|
||||
this.selectImagePictureBox.TabStop = false;
|
||||
//
|
||||
// infoTextBox
|
||||
//
|
||||
this.infoTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.infoTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
|
||||
this.infoTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.infoTextBox, 2);
|
||||
this.infoTextBox.Cursor = System.Windows.Forms.Cursors.Arrow;
|
||||
this.infoTextBox.ForeColor = System.Drawing.SystemColors.Window;
|
||||
this.infoTextBox.Location = new System.Drawing.Point(3, 235);
|
||||
this.infoTextBox.Name = "infoTextBox";
|
||||
this.infoTextBox.ReadOnly = true;
|
||||
this.infoTextBox.Size = new System.Drawing.Size(296, 253);
|
||||
this.infoTextBox.TabIndex = 15;
|
||||
this.infoTextBox.TabStop = false;
|
||||
this.infoTextBox.Text = "";
|
||||
//
|
||||
// replaceButton
|
||||
//
|
||||
this.replaceButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.replaceButton.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.replaceButton, 2);
|
||||
this.replaceButton.Location = new System.Drawing.Point(3, 519);
|
||||
this.replaceButton.Name = "replaceButton";
|
||||
this.replaceButton.Size = new System.Drawing.Size(296, 23);
|
||||
this.replaceButton.TabIndex = 14;
|
||||
this.replaceButton.Text = "Replace";
|
||||
this.replaceButton.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.replaceButton.UseSelectable = true;
|
||||
this.replaceButton.Click += new System.EventHandler(this.replaceButton_Click);
|
||||
//
|
||||
// animationButton
|
||||
//
|
||||
this.animationButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.animationButton.AutoSize = true;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.animationButton, 2);
|
||||
this.animationButton.Location = new System.Drawing.Point(3, 494);
|
||||
this.animationButton.Name = "animationButton";
|
||||
this.animationButton.Size = new System.Drawing.Size(296, 19);
|
||||
this.animationButton.TabIndex = 16;
|
||||
this.animationButton.Text = "Animation";
|
||||
this.animationButton.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.animationButton.UseSelectable = true;
|
||||
this.animationButton.Click += new System.EventHandler(this.animationButton_Click);
|
||||
//
|
||||
// TextureAtlasEditor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(799, 649);
|
||||
this.Controls.Add(this.tableLayoutPanel1);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.Name = "TextureAtlasEditor";
|
||||
this.ShadowType = MetroFramework.Forms.MetroFormShadowType.None;
|
||||
this.Style = MetroFramework.MetroColorStyle.Silver;
|
||||
this.Text = "Texture Atlas Editor";
|
||||
this.Theme = MetroFramework.MetroThemeStyle.Dark;
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.originalPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.selectImagePictureBox)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private PictureBoxWithInterpolationMode selectImagePictureBox;
|
||||
private MetroFramework.Controls.MetroButton prevButton;
|
||||
private MetroFramework.Controls.MetroButton nextButton;
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
|
||||
private MetroFramework.Controls.MetroButton replaceButton;
|
||||
private PictureBoxWithInterpolationMode originalPictureBox;
|
||||
private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
|
||||
private System.Windows.Forms.RichTextBox infoTextBox;
|
||||
private MetroFramework.Controls.MetroButton animationButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem extractTileToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
339
PCK-Studio/Forms/Editor/TextureAtlasEditor.cs
Normal file
339
PCK-Studio/Forms/Editor/TextureAtlasEditor.cs
Normal file
@@ -0,0 +1,339 @@
|
||||
/* Copyright (c) 2023-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using MetroFramework.Forms;
|
||||
using OMI.Formats.Pck;
|
||||
using PckStudio.Extensions;
|
||||
using PckStudio.Forms.Editor;
|
||||
using PckStudio.Forms.Utilities;
|
||||
|
||||
namespace PckStudio
|
||||
{
|
||||
internal partial class TextureAtlasEditor : MetroForm
|
||||
{
|
||||
public Image FinalTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (DialogResult != DialogResult.OK)
|
||||
return null;
|
||||
return (Image)originalPictureBox.Image.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
private struct SelectedTile
|
||||
{
|
||||
internal readonly int Index;
|
||||
internal readonly string Name;
|
||||
internal readonly string TextureName;
|
||||
internal readonly Rectangle Area;
|
||||
|
||||
public SelectedTile(int index, string name, string textureName, Rectangle area)
|
||||
{
|
||||
Index = index;
|
||||
Name = name;
|
||||
TextureName = textureName;
|
||||
Area = area;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly PckFile _pckFile;
|
||||
private readonly Size _areaSize;
|
||||
private readonly int _rowCount;
|
||||
private readonly int _columnCount;
|
||||
private readonly string _atlasType;
|
||||
private readonly List<Image> _textures;
|
||||
private readonly List<AnimationResources.TileInfo> _textureInfos;
|
||||
|
||||
private SelectedTile _selectedItem = new SelectedTile();
|
||||
private int SelectedIndex
|
||||
{
|
||||
set => SetImageDisplayed(value);
|
||||
}
|
||||
|
||||
private const ImageLayoutDirection _imageLayout = ImageLayoutDirection.Horizontal;
|
||||
|
||||
public TextureAtlasEditor(PckFile pckFile, string path, Image atlas, Size areaSize)
|
||||
{
|
||||
InitializeComponent();
|
||||
_areaSize = areaSize;
|
||||
_pckFile = pckFile;
|
||||
_rowCount = atlas.Width / areaSize.Width;
|
||||
_columnCount = atlas.Height / areaSize.Height;
|
||||
(_textureInfos, _atlasType) = Path.GetFileNameWithoutExtension(path) switch
|
||||
{
|
||||
"terrain" => (AnimationResources.BlockTileInfos, "blocks"),
|
||||
"items" => (AnimationResources.ItemTileInfos, "items"),
|
||||
_ => (null, null),
|
||||
};
|
||||
originalPictureBox.Image = atlas;
|
||||
var images = atlas.CreateImageList(_areaSize, _imageLayout);
|
||||
_textures = new List<Image>(images);
|
||||
SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void SetImageDisplayed(int index)
|
||||
{
|
||||
prevButton.Enabled = index > 0;
|
||||
nextButton.Enabled = index < _textures.Count - 1;
|
||||
infoTextBox.Text = string.Empty;
|
||||
|
||||
if (_textureInfos is not null && _textureInfos.IndexInRange(index))
|
||||
{
|
||||
var info = _textureInfos[index];
|
||||
var pos = GetSelectedPoint(index, _rowCount, _columnCount, _imageLayout);
|
||||
var selectedArea = new Rectangle(pos.X * _areaSize.Width, pos.Y * _areaSize.Height, _areaSize.Width, _areaSize.Height);
|
||||
_selectedItem = new SelectedTile(index, info.DisplayName, info.InternalName, selectedArea);
|
||||
|
||||
infoTextBox.Text = $"{_selectedItem.Name}\n{_selectedItem.TextureName}";
|
||||
animationButton.Text =
|
||||
_pckFile.Files.Contains($"res/textures/{_atlasType}/{_selectedItem.TextureName}.png", PckFile.FileData.FileType.TextureFile)
|
||||
? "Open Animation"
|
||||
: "Create Animation";
|
||||
}
|
||||
|
||||
if (_textures.IndexInRange(index))
|
||||
{
|
||||
selectImagePictureBox.Image = _textures[index];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void prevButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
SelectedIndex = _selectedItem.Index - 1;
|
||||
}
|
||||
|
||||
private void nextButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
SelectedIndex = _selectedItem.Index + 1;
|
||||
}
|
||||
|
||||
private void originalPictureBox_MouseClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button != MouseButtons.Left)
|
||||
return;
|
||||
|
||||
var index = GetSelectedImageIndex(
|
||||
originalPictureBox.Size,
|
||||
originalPictureBox.Image.Size,
|
||||
_areaSize,
|
||||
e.Location,
|
||||
originalPictureBox.SizeMode,
|
||||
_imageLayout);
|
||||
|
||||
Debug.WriteLine(index);
|
||||
if (index != -1)
|
||||
{
|
||||
SelectedIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetSelectedImageIndex(
|
||||
Size pictureBoxSize,
|
||||
Size imageSize,
|
||||
Size areaSize,
|
||||
Point clickLocation,
|
||||
PictureBoxSizeMode sizeMode,
|
||||
ImageLayoutDirection imageLayout)
|
||||
{
|
||||
Point result = new Point();
|
||||
int rowCount = imageSize.Width / areaSize.Width;
|
||||
int columnCount = imageSize.Height / areaSize.Height;
|
||||
switch (sizeMode)
|
||||
{
|
||||
case PictureBoxSizeMode.Normal:
|
||||
case PictureBoxSizeMode.AutoSize:
|
||||
{
|
||||
var imageArea = new Rectangle(Point.Empty, imageSize);
|
||||
if (!imageArea.Contains(clickLocation))
|
||||
return -1;
|
||||
result.X = clickLocation.X / areaSize.Width;
|
||||
result.Y = clickLocation.Y / areaSize.Height;
|
||||
break;
|
||||
}
|
||||
case PictureBoxSizeMode.StretchImage:
|
||||
{
|
||||
float widthDiff = (float)pictureBoxSize.Width / imageSize.Width;
|
||||
float heightDiff = (float)pictureBoxSize.Height / imageSize.Height;
|
||||
Size scaledArea = Size.Round(new SizeF(areaSize.Width * widthDiff, areaSize.Height * heightDiff));
|
||||
|
||||
result.X = clickLocation.X / scaledArea.Width;
|
||||
result.Y = clickLocation.Y / scaledArea.Height;
|
||||
break;
|
||||
}
|
||||
case PictureBoxSizeMode.CenterImage:
|
||||
{
|
||||
Rectangle imageArea = new Rectangle(Point.Empty, imageSize);
|
||||
imageArea.X = (pictureBoxSize.Width - imageArea.Width) / 2;
|
||||
imageArea.Y = (pictureBoxSize.Height - imageArea.Height) / 2;
|
||||
|
||||
if (!imageArea.Contains(clickLocation))
|
||||
return -1;
|
||||
|
||||
result.X = (clickLocation.X - imageArea.X) / (clickLocation.X * areaSize.Width);
|
||||
result.Y = (clickLocation.Y - imageArea.Y) / (clickLocation.Y * areaSize.Height);
|
||||
break;
|
||||
}
|
||||
case PictureBoxSizeMode.Zoom:
|
||||
{
|
||||
Rectangle imageArea = new Rectangle();
|
||||
float widthDiff = (float)pictureBoxSize.Width / imageSize.Width;
|
||||
float heightDiff = (float)pictureBoxSize.Height / imageSize.Height;
|
||||
float scale = Math.Min(widthDiff, heightDiff);
|
||||
|
||||
imageArea.Width = (int)(imageSize.Width * scale);
|
||||
imageArea.Height = (int)(imageSize.Height * scale);
|
||||
imageArea.X = (pictureBoxSize.Width - imageArea.Width) / 2;
|
||||
imageArea.Y = (pictureBoxSize.Height - imageArea.Height) / 2;
|
||||
|
||||
if (!imageArea.Contains(clickLocation))
|
||||
return -1;
|
||||
|
||||
Size scaledArea = Size.Round(new SizeF(areaSize.Width * scale, areaSize.Height * scale));
|
||||
result.X = (clickLocation.X - imageArea.X) / scaledArea.Width;
|
||||
result.Y = (clickLocation.Y - imageArea.Y) / scaledArea.Height;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return GetSelectedIndex(result.X, result.Y, rowCount, columnCount, imageLayout);
|
||||
}
|
||||
|
||||
private static int GetSelectedIndex(int x, int y, int rowCount, int columnCount, ImageLayoutDirection imageLayout)
|
||||
{
|
||||
return imageLayout switch
|
||||
{
|
||||
ImageLayoutDirection.Horizontal => x + y * rowCount,
|
||||
ImageLayoutDirection.Vertical => y + x * columnCount,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(imageLayout)),
|
||||
};
|
||||
}
|
||||
|
||||
private static Point GetSelectedPoint(int index, int rowCount, int columnCount, ImageLayoutDirection imageLayout)
|
||||
{
|
||||
int y = Math.DivRem(index, rowCount, out int x);
|
||||
if (imageLayout == ImageLayoutDirection.Vertical)
|
||||
x = Math.DivRem(index, columnCount, out y);
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
private void replaceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenFileDialog fileDialog = new OpenFileDialog()
|
||||
{
|
||||
Filter = "PNG Image|*.png",
|
||||
Title = "Select Texture"
|
||||
};
|
||||
|
||||
if (fileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
var img = Image.FromFile(fileDialog.FileName);
|
||||
SetTile(img);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTile(Image texture)
|
||||
{
|
||||
var graphicsConfig = new GraphicsConfig()
|
||||
{
|
||||
InterpolationMode = selectImagePictureBox.InterpolationMode,
|
||||
PixelOffsetMode = PixelOffsetMode.HighQuality
|
||||
};
|
||||
if (texture.Size != _areaSize)
|
||||
texture = texture.ResizeImage(_areaSize, graphicsConfig);
|
||||
using (var g = Graphics.FromImage(originalPictureBox.Image))
|
||||
{
|
||||
g.ApplyConfig(graphicsConfig);
|
||||
g.Fill(_selectedItem.Area, Color.Transparent);
|
||||
g.DrawImage(texture, _selectedItem.Area);
|
||||
}
|
||||
_textures[_selectedItem.Index] = texture;
|
||||
selectImagePictureBox.Image = texture;
|
||||
originalPictureBox.Invalidate();
|
||||
}
|
||||
|
||||
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
DialogResult = DialogResult.OK;
|
||||
}
|
||||
|
||||
private void animationButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
bool isNewFile;
|
||||
if (isNewFile = !_pckFile.Files.TryGetValue(
|
||||
$"res/textures/{_atlasType}/{_selectedItem.TextureName}.png",
|
||||
PckFile.FileData.FileType.TextureFile, out var file
|
||||
))
|
||||
{
|
||||
file = new PckFile.FileData($"res/textures/{_atlasType}/{_selectedItem.TextureName}.png", PckFile.FileData.FileType.TextureFile);
|
||||
}
|
||||
var animationEditor = new AnimationEditor(file);
|
||||
if (animationEditor.ShowDialog() == DialogResult.OK && isNewFile)
|
||||
{
|
||||
_pckFile.Files.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveFileDialog saveFileDialog = new SaveFileDialog()
|
||||
{
|
||||
Filter = "Tile Texture|*.png",
|
||||
FileName = _selectedItem.TextureName
|
||||
};
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
selectImagePictureBox.Image.Save(saveFileDialog.FileName, ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ProcessDialogKey(Keys keyData)
|
||||
{
|
||||
switch (keyData)
|
||||
{
|
||||
case Keys.Left:
|
||||
if (prevButton.Enabled)
|
||||
{
|
||||
prevButton_Click(this, EventArgs.Empty);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case Keys.Right:
|
||||
if (nextButton.Enabled)
|
||||
{
|
||||
nextButton_Click(this, EventArgs.Empty);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
// return base.ProcessDialogKey(keyData);
|
||||
}
|
||||
}
|
||||
}
|
||||
2630
PCK-Studio/Forms/Editor/TextureAtlasEditor.resx
Normal file
2630
PCK-Studio/Forms/Editor/TextureAtlasEditor.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -367,14 +367,35 @@ namespace PckStudio
|
||||
|
||||
private void HandleTextureFile(PckFile.FileData file)
|
||||
{
|
||||
if (!(file.Filename.StartsWith("res/textures/blocks/") || file.Filename.StartsWith("res/textures/items/")))
|
||||
return;
|
||||
_ = file.IsMipmappedFile() && currentPCK.Files.TryGetValue(file.GetNormalPath(), PckFile.FileData.FileType.TextureFile, out file);
|
||||
|
||||
if (file.IsMipmappedFile() && currentPCK.Files.TryGetValue(file.GetNormalPath(), PckFile.FileData.FileType.TextureFile, out PckFile.FileData originalAnimationFile))
|
||||
if (file.Size <= 0)
|
||||
{
|
||||
file = originalAnimationFile;
|
||||
Debug.WriteLine($"'{file.Filename}' size is 0.", category: nameof(HandleTextureFile));
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.Filename == "res/terrain.png" || file.Filename == "res/items.png")
|
||||
{
|
||||
using var ms = new MemoryStream(file.Data);
|
||||
|
||||
var img = Image.FromStream(ms);
|
||||
var res = img.Width / 16; // texture count on X axes
|
||||
var size = new Size(res, res);
|
||||
var viewer = new TextureAtlasEditor(currentPCK, file.Filename, img, size);
|
||||
if (viewer.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
using (var result = new MemoryStream())
|
||||
{
|
||||
viewer.FinalTexture.Save(result, ImageFormat.Png);
|
||||
file.SetData(result.ToArray());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.Filename.StartsWith("res/textures/blocks/") || file.Filename.StartsWith("res/textures/items/"))
|
||||
{
|
||||
using (AnimationEditor animationEditor = new AnimationEditor(file))
|
||||
{
|
||||
if (animationEditor.ShowDialog(this) == DialogResult.OK)
|
||||
@@ -383,6 +404,8 @@ namespace PckStudio
|
||||
BuildMainTreeView();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleGameRuleFile(PckFile.FileData file)
|
||||
|
||||
@@ -196,6 +196,12 @@
|
||||
<DependentUpon>AppSettingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Internal\ApplicationBuildInfo.cs" />
|
||||
<Compile Include="Forms\Editor\TextureAtlasEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Forms\Editor\TextureAtlasEditor.Designer.cs">
|
||||
<DependentUpon>TextureAtlasEditor.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Classes\API\PCKCenter\model\PCKCenterJSON.cs" />
|
||||
<Compile Include="Classes\API\PCKCenter\PCKCollections.cs" />
|
||||
<Compile Include="Classes\API\PCKCenter\PCKCollectionsLocal.cs" />
|
||||
@@ -594,6 +600,9 @@
|
||||
<DependentUpon>AppSettingsForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Forms\Editor\TextureAtlasEditor.resx">
|
||||
<DependentUpon>TextureAtlasEditor.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="MainForm.ja.resx">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
Reference in New Issue
Block a user